Compare commits

...

180 Commits

Author SHA1 Message Date
4c766f82db Merge pull request #774 from Kilig947/wps_i18n
UI界面优化
2023-07-01 22:13:57 +08:00
f730894944 Merge branch 'ui_improvement' into wps_i18n 2023-07-01 22:13:38 +08:00
380952679e initialize UI improvement 2023-07-01 22:11:39 +08:00
b44c0f471d 修复pick 导致的问题 2023-07-01 18:21:23 +08:00
4cd1f5d71e 适配手机端1.0, 2023-07-01 18:14:46 +08:00
f247734cee 同步css代码 2023-07-01 15:14:21 +08:00
1acb8aec93 修复多线程性能问题 2023-07-01 14:54:04 +08:00
ae92b7f5ef 跳转链接优化 2023-07-01 14:47:31 +08:00
fffd580e14 修复多线程性能问题 2023-07-01 14:46:16 +08:00
7cbacdf7c2 快捷栏新增一个选项 2023-07-01 14:45:46 +08:00
3e479fbf73 合并master 2023-06-30 16:19:57 +08:00
571d952b24 stop 替换为 primary, 按钮保持双色系,太多颜色眼花缭乱 2023-06-27 17:22:23 +08:00
61e3945547 解决合并川虎导致 Prompt 重复的bug 2023-06-27 16:40:13 +08:00
bd0fd4fd68 解决一些合并冲突遗漏 2023-06-27 16:00:53 +08:00
0fb08d7d9e 对话记录以及Prompt,试用Accordion容器控制 2023-06-27 15:59:28 +08:00
945ea82d0e 合并川虎js, 舍弃他的对话历史逻辑 2023-06-27 15:59:22 +08:00
235fd44460 再修改亿些细节 2023-06-27 15:58:54 +08:00
abce963099 修改川虎UI细节,为后续支持多模态输入做准备 2023-06-27 15:58:27 +08:00
38b4215568 合并川虎UI 细节 2023-06-27 15:58:20 +08:00
8046900b89 解决一些合并冲突遗漏 2023-06-27 15:54:20 +08:00
8bcb8dee18 增加段落markdown 样式 2023-06-27 15:51:14 +08:00
f2ee6c3d95 解决一些合并冲突遗漏 2023-06-27 15:29:53 +08:00
37ebab43d2 合并master,删除不必要的文件 2023-06-27 15:20:29 +08:00
7bf8ba86a4 Revert "合并开发分支代码"
This reverts commit 54423fd178.

丢弃这个修改
2023-06-27 15:20:28 +08:00
556ab94181 更新Latex模块的docker-compose 2023-06-27 15:20:28 +08:00
e20363ee2a arxiv PDF 引用 2023-06-27 15:20:28 +08:00
a37f94a6d6 修正误判latex模板文件的bug 2023-06-27 15:20:28 +08:00
0aa1fa6293 add arxiv translation test samples 2023-06-27 15:20:28 +08:00
449d45815e Your commit message 2023-06-27 15:20:25 +08:00
29ec163be6 update azure use instruction 2023-06-27 15:19:14 +08:00
4c460a58c1 当遇到错误时,回滚到原文 2023-06-27 15:19:14 +08:00
de175d04b9 更新接入azure的说明 2023-06-27 15:19:11 +08:00
b48eff42c9 增加azure openai api的支持 2023-06-27 15:18:46 +08:00
d67cb5a872 update test samples 2023-06-27 15:18:14 +08:00
4862db0669 Create build-with-latex.yml 2023-06-27 15:18:14 +08:00
46a702d9cd Update README.md
Fix the error URL for the git clone.
2023-06-27 15:18:14 +08:00
9a090bfa4b add latex docker-compose 2023-06-27 15:18:14 +08:00
fe3f28448a fix minor bugs 2023-06-27 15:18:10 +08:00
d92b3a214d fix bugs 2023-06-27 15:16:58 +08:00
96ed81f486 fix encoding bug 2023-06-27 15:14:25 +08:00
8194f9353d avoid file fusion 2023-06-27 15:14:25 +08:00
965632c2b8 Update README.md 2023-06-27 15:14:25 +08:00
4156067df7 Update README.md 2023-06-27 15:14:25 +08:00
c61c64de55 Update README.md 2023-06-27 15:14:25 +08:00
1ba8d9ca28 Update Latex输出PDF结果.py 2023-06-27 15:14:25 +08:00
5cf15eaf6c Update README.md 2023-06-27 15:14:25 +08:00
a52cfa03c6 Update README.md 2023-06-27 15:14:25 +08:00
d1128fd067 增加一些提示文字 2023-06-27 15:14:25 +08:00
52fd21a921 修复Langchain插件的bug 2023-06-27 15:14:25 +08:00
e6e2c338ec 合并修改 2023-06-27 15:14:09 +08:00
c7d8ef63a3 temp 2023-06-27 15:11:43 +08:00
cc07b1849c 漏掉的Key补充上 2023-06-27 14:10:38 +08:00
54423fd178 合并开发分支代码 2023-06-27 14:04:52 +08:00
232c181a4b 对话记录以及Prompt,试用Accordion容器控制 2023-06-27 13:59:50 +08:00
db6435474f 合并川虎js, 舍弃他的对话历史逻辑 2023-06-27 13:59:47 +08:00
df320ea4fc 再修改亿些细节 2023-06-27 13:59:44 +08:00
6d0c55f2c8 修改川虎UI细节,为后续支持多模态输入做准备 2023-06-27 13:59:41 +08:00
c38a532658 合并川虎UI 细节 2023-06-27 13:59:33 +08:00
b2468e065c pick 部分代码 2023-06-27 13:58:09 +08:00
670b5b0f5b pick 部分代码 2023-06-27 13:56:52 +08:00
d8ec10e859 增加段落markdown 样式 2023-06-27 13:54:44 +08:00
1e0e55df3a pick 部分代码 2023-06-27 13:52:55 +08:00
5ad71f39da 修复匹配单个美元符号的问题 2023-06-27 13:51:45 +08:00
2333b4e8ef 提交一部分代码,优化结构 2023-06-27 13:51:42 +08:00
56679a41ef pick 部分代码 2023-06-27 13:51:32 +08:00
fbe9bcac96 优化代码 2023-06-27 13:50:06 +08:00
c7add2dd11 增加刷新页面时重载Prompt 数据,关联Prompt和搜索条件,当选择个人时,只会搜到自己的记录 2023-06-27 13:49:58 +08:00
0624bf6e89 pick 部分代码 2023-06-27 13:49:51 +08:00
d1531c9ddc 优化代码! 真的最有一次优化isay的逻辑了!!!! 2023-06-16 20:01:44 +08:00
4774dad8ab 再次解决isay 换行显示问题 2023-06-16 12:34:25 +08:00
8ac9fe97cd 解决prompt 代码块开头不显示的bug 2023-06-15 14:17:16 +08:00
d4befe6964 优化isay 代码,考虑代码块内有```和有制表符的情况, 优化界面显示 2023-06-15 12:49:04 +08:00
c8c4d37616 合并master 2023-06-14 11:08:50 +08:00
fe16cc76a7 config 默认配置 2023-06-13 15:54:20 +08:00
b3f9566d19 刷页面loading 不做多操作,优化刷新页面时抖动的情况,搜索prompt大小写适配 2023-06-12 19:07:12 +08:00
ac7d82380a 修复复用prompt的bug 2023-06-12 18:37:45 +08:00
b42fbdd0cf 优化界面显示 2023-06-12 18:37:45 +08:00
db1e3460d3 优化界面显示 2023-06-12 18:37:45 +08:00
f995df726b 对话时增加等待过渡 2023-06-12 18:37:45 +08:00
f74dd47d01 适配网关3.5 2023-06-09 10:33:54 +08:00
955367b0bc 适配ai网关应用 2023-06-08 20:17:38 +08:00
1ac5f934f2 增加每次对话统计tokens 2023-06-08 13:11:15 +08:00
536687bb71 优化细节~ 2023-06-08 12:24:50 +08:00
11406f5c2a 复用prompt, 可以选择继承所有上下文 2023-06-08 12:10:56 +08:00
0a6bb18a2e 优化prompt 搜索,将所有上下文一起展示 2023-06-08 11:51:31 +08:00
f2cfc44b02 特殊操作封装成方法 2023-06-06 17:29:10 +08:00
3dcf3cf981 优化搜索prompt速度 2023-06-06 16:47:11 +08:00
d818ba1be2 过滤数据库中多余的数据 2023-06-06 14:23:52 +08:00
b8455d9acb 删除不必要代码 2023-06-06 12:40:09 +08:00
a2c02636fa 将数据库的prompt换为UNIQUE唯一属性,并且插入语句换成REPLACE INTO 2023-06-06 12:28:02 +08:00
86c8184d20 换一种方式判断 2023-06-06 12:00:18 +08:00
91621af63f 解决首次调用基础功能,输入框为空报错的问题 2023-06-06 11:54:08 +08:00
4112db7a60 插件列表默认展示 2023-06-07 10:51:29 +08:00
1cbb410807 pick auto 部分修改 2023-06-07 10:44:58 +08:00
2bafcab043 增加复用prompt功能 2023-06-07 10:39:57 +08:00
12c4609712 优化chatbot 显示效果,重写chatbot的css 代码,让其最大不超过父元素 2023-06-05 10:23:09 +08:00
7b83ba6c47 修复写入错误的库文件,增加统计单次对话耗时 2023-06-05 10:23:03 +08:00
b11807f35d 移除autogpt 相关代码,autogpt 在新分支开发 2023-06-05 10:14:22 +08:00
8ab0c1b6e5 合并master 2023-06-04 20:26:04 +08:00
12b9c94c60 重启autogpt 2023-06-04 20:15:30 +08:00
d8759c5863 优化展示|优化对话时清空输入框逻辑 2023-06-03 02:03:14 +08:00
954822b16b 修改注释 2023-06-02 21:39:26 +08:00
85e73e731f 优化页面样式,对齐市面上左导航右对话的布局|修复输入框为空时,调用功能仍正常对话 2023-06-02 21:39:05 +08:00
213233cd60 优化isay markdown 2023-05-31 16:14:40 +08:00
c9f334b647 优化isay markdown 2023-05-31 12:08:12 +08:00
519df19f43 autogpt 还原,开新分支编写 2023-05-30 16:38:01 +08:00
548532e522 更新autogptadd 2023-05-30 15:48:14 +08:00
cfa885a04e 更新autogpt 2023-05-30 15:44:39 +08:00
942607a576 适配markdown 换行 2023-05-29 12:36:30 +08:00
5e201222bb 还原被删除的auto-gpt 2023-05-29 12:34:12 +08:00
2b28f29681 Revert "适配markdown 换行"
This reverts commit 7e75b6e7ab.

回滚
2023-05-29 12:18:59 +08:00
36c1cefb9a Merge branch 'wps_i18n' of https://ksogitlab.wps.kingsoft.net/w_xiaolizu/chatbot-for-kso into wps_i18n
mrege
2023-05-29 12:11:08 +08:00
7e75b6e7ab 适配markdown 换行 2023-05-29 12:09:45 +08:00
c5178b7038 入库prompt字符串从strip替换为正则表达式 2023-05-29 11:44:48 +08:00
90325d6056 修复二级路径的文件屏蔽 2023-05-29 11:44:48 +08:00
b362c87b39 修复Gradio配置泄露的问题 2023-05-29 11:44:48 +08:00
03aa2ee115 入库prompt字符串从strip替换为正则表达式 2023-05-29 11:27:53 +08:00
d804fc11f8 Merge branch 'master' into wps_i18n
合并master
2023-05-29 10:24:15 +08:00
ae1ab14a75 ignore third party 2023-05-28 19:08:42 +08:00
0c9cf5f4d9 Merge branch 'wps_i18n' of https://github.com/Kilig947/gpt_academic into Kilig947-wps_i18n 2023-05-28 19:07:41 +08:00
c8dbd66bca 适配白色模式,字体不再发灰 2023-05-26 16:36:58 +08:00
360da3f8c2 合并mater 2023-05-26 14:28:19 +08:00
7c7f1891b7 修复录入数据库数据错误 2023-05-23 19:40:14 +08:00
1f976da3fa 恢复重置按钮 2023-05-23 19:26:25 +08:00
aa09c3f6f2 删除不必要的库 2023-05-23 19:19:49 +08:00
97ae740e52 固定端口号OC 2023-05-23 18:41:01 +08:00
ac45f1036b 默认不打开浏览器,太麻烦了,每次部署上服务器都要关 2023-05-23 18:38:58 +08:00
c250b6d789 优化界面显示|将say也转换为markdwon 格式,并且不做多处理|增强user 和 bot 的对比 2023-05-23 18:32:23 +08:00
065257b6d8 修复高级参数bug 2023-05-23 10:49:34 +08:00
11cbfd33e9 修改文案 2023-05-22 18:19:53 +08:00
9b2bc97b67 删除多余代码|增加代码注释 2023-05-22 16:51:46 +08:00
331ab3be0d Merge branch 'master' into wps_i18n 2023-05-22 12:10:10 +08:00
7a8b50102d 增加文案优化 2023-05-22 11:58:42 +08:00
9f871deb4d 过滤对话的html代码 2023-05-22 10:35:28 +08:00
bf6f5c433d 更改插件tab名 2023-05-19 19:10:04 +08:00
6aec31c2ba 注释代码调整 2023-05-19 14:01:21 +08:00
53af439791 优化编辑和历史的页面 2023-05-19 13:59:47 +08:00
5a7e08f615 合并master 2023-05-19 13:05:03 +08:00
6ff7b88ad5 优化排版 2023-05-19 13:03:00 +08:00
7b6aa5c0b1 还原一些操作 2023-05-18 22:01:20 +08:00
7bb7062f55 autogpt 的库文件 2023-05-18 21:19:24 +08:00
752ba5a61f 将配置文件读取目录网上一层,增加安全性 2023-05-18 21:07:17 +08:00
f94cbe7923 固定端口号 2023-05-18 20:45:37 +08:00
456a599535 Merge branch 'master' into wps_i18n
合并msater
2023-05-18 15:38:28 +08:00
1aa68c14ea 解决刷新dataset的bug 2023-05-18 14:45:08 +08:00
1e28a4feea 将文件存储换成sqlite3 | 对话可以更多花样 2023-05-17 21:48:19 +08:00
c5d4f60137 将文件存储换成sqlite3 | 对话可以更多花样 2023-05-17 21:46:39 +08:00
e6c4bf1881 高级用法的函数加入下拉列表 2023-05-16 11:06:10 +08:00
e505c95148 优化提交内容 2023-05-15 16:49:33 +08:00
7e07ccf040 修复下拉插件和普通问答的bug 2023-05-15 13:34:49 +08:00
7f64f2a00f 支持函数高级用法 2023-05-14 21:55:34 +08:00
61dc6f296f 解决下拉插件不适配ipaddr的问题 2023-05-14 21:23:16 +08:00
ba51bac7e1 Merge branch 'master' into wps_i18n
合并master
2023-05-14 20:04:44 +08:00
be0b274aa2 增加私密模式 2023-05-14 20:04:12 +08:00
3cc6eeb314 增加prompt 检索和编辑器|增加prompt 展示 2023-05-11 17:05:19 +08:00
03f0f49847 Merge branch 'master' into wps_i18n
yes
2023-05-08 10:31:12 +08:00
519d0a1f42 增加prompt收集统计 2023-05-08 10:30:23 +08:00
808aecab91 合并master 2023-05-05 11:27:54 +08:00
c1aebca6a3 解决下拉插件的问题哦 2023-04-28 18:17:54 +08:00
26c20ed2f5 解决冲突,合并master 2023-04-28 09:58:16 +08:00
4f7ff3bb42 增加auto-gpt0.5版本 2023-04-28 09:53:51 +08:00
5ed93b36c9 Merge branch 'master' into wps_i18n
merge master
2023-04-24 10:46:13 +08:00
859e3c0b9d update 2023-04-24 10:45:36 +08:00
f764b76694 修改页面,适配笔记本页面~ 2023-04-23 11:14:57 +08:00
94df191060 合并master修改 2023-04-23 10:04:32 +08:00
3f4e4ba261 update 2023-04-23 09:41:38 +08:00
114fc12ffe Merge branch 'master' into wps_i18n
合并master

.
2023-04-21 17:13:57 +08:00
73c6a2aeb0 增加基础功能判空 2023-04-21 17:09:49 +08:00
fd6b1755c9 增加下载文件功能 2023-04-21 15:40:21 +08:00
472b6a88b4 修改上传文件逻辑:不再删除文件、保留用户文件|增加用户获取历史上传记录 2023-04-20 16:19:48 +08:00
8764ae3cb8 试用插件完成预测输入 2023-04-19 23:01:22 +08:00
c6942060e4 删除显示隐藏功能区域 2023-04-19 21:50:45 +08:00
9f3194619b 增加打印用户信息 2023-04-19 21:38:47 +08:00
7a17eb2c9d 另外一种方式导包 2023-04-19 21:01:36 +08:00
fe6850a0bb 另外一种方式实现ipadder 2023-04-19 19:34:31 +08:00
ee73573655 合并master 2023-04-19 18:48:47 +08:00
b8e20f5aae 搞点东西 2023-04-19 18:37:43 +08:00
7bb005c13b 增加关键字加密功能 2023-04-19 14:15:39 +08:00
fa141fe5f8 强调完整翻译 2023-04-19 10:05:19 +08:00
de2ad563ef 修改页面布局|增加访问者ip打印 2023-04-19 09:52:03 +08:00
33 changed files with 3264 additions and 300 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

44
.gitignore vendored
View File

@ -2,15 +2,14 @@
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
plugins/
downloads/
eggs/
.eggs/
@ -26,7 +25,6 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
@ -35,7 +33,6 @@ MANIFEST
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
@ -49,91 +46,64 @@ coverage.xml
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
github
.github
TEMP
TRASH
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
site/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.direnv/
.venv
env/
venv/
venv*/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
.vscode
.idea
history
ssr_conf
config_private.py
@ -145,8 +115,12 @@ cradle*
debug*
private*
crazy_functions/test_project/pdf_and_word
crazy_fun
ctions/test_samples
crazy_functions/test_samples
request_llm/jittorllms
multi-language
users_data/*
request_llm/moss
multi-language
media
__test.py

486
__main__.py Normal file
View File

@ -0,0 +1,486 @@
import os
import gradio as gr
from request_llm.bridge_all import predict
from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_user_upload, \
get_conf, ArgsGeneralWrapper, DummyWith
# 问询记录, python 版本建议3.9+(越新越好)
import logging
# 一些普通功能模块
from core_functional import get_core_functions
functional = get_core_functions()
# 高级函数插件
from crazy_functional import get_crazy_functions
crazy_fns = get_crazy_functions()
# 处理markdown文本格式的转变
gr.Chatbot.postprocess = format_io
# 做一些外观色彩上的调整
from theme import adjust_theme, advanced_css, custom_css
set_theme = adjust_theme()
# 代理与自动更新
from check_proxy import check_proxy, auto_update, warm_up_modules
import func_box
from check_proxy import get_current_version
os.makedirs("gpt_log", exist_ok=True)
try:
logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO, encoding="utf-8")
except:
logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO)
print("所有问询记录将自动保存在本地目录./gpt_log/chat_secrets.log, 请注意自我隐私保护哦!")
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到
proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION, LAYOUT, API_KEY, AVAIL_LLM_MODELS, LOCAL_PORT= \
get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION', 'LAYOUT',
'API_KEY', 'AVAIL_LLM_MODELS', 'LOCAL_PORT')
proxy_info = check_proxy(proxies)
# 如果WEB_PORT是-1, 则随机选取WEB端口
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
if not AUTHENTICATION: AUTHENTICATION = None
os.environ['no_proxy'] = '*' # 避免代理网络产生意外污染
class ChatBotFrame:
def __init__(self):
self.cancel_handles = []
self.initial_prompt = "You will play a professional to answer me according to my needs."
self.title_html = f"<h1 align=\"center\">Chatbot for KSO {get_current_version()}</h1>"
self.description = """代码开源和更新[地址🚀](https://github.com/binary-husky/chatgpt_academic),感谢热情的[开发者们❤️](https://github.com/binary-husky/chatgpt_academic/graphs/contributors)"""
class ChatBot(ChatBotFrame):
def __init__(self):
super().__init__()
self.__url = f'http://{func_box.ipaddr()}:{PORT}'
# self.__gr_url = gr.State(self.__url)
def draw_title(self):
# self.title = gr.HTML(self.title_html)
self.cookies = gr.State({'api_key': API_KEY, 'llm_model': LLM_MODEL, 'local': self.__url})
def draw_chatbot(self):
self.chatbot = gr.Chatbot(elem_id='main_chatbot', label=f"当前模型:{LLM_MODEL}")
self.chatbot.style()
self.history = gr.State([])
temp_draw = [gr.HTML() for i in range(7)]
with gr.Box(elem_id='chat_box'):
self.state_users = gr.HTML(value='', visible=False, elem_id='state_users')
with gr.Row():
self.sm_upload = gr.UploadButton(label='UPLOAD', file_count='multiple', elem_classes='sm_btn').style(size='sm', full_width=False)
self.sm_code_block = gr.Button(value='CODE', elem_classes='sm_btn').style(size='sm', full_width=False)
self.sm_upload_history = gr.Button("SPASE", variant="primary", elem_classes='sm_btn').style(size='sm', full_width=False)
self.md_dropdown = gr.Dropdown(choices=AVAIL_LLM_MODELS, value=LLM_MODEL,
show_label=False, interactive=True,
elem_classes='sm_select', elem_id='change-font-size').style(container=False)
gr.HTML(func_box.get_html("appearance_switcher.html").format(label=""), elem_id='user_input_tb', elem_classes="insert_block")
with gr.Row():
self.txt = gr.Textbox(show_label=False, placeholder="Input question here.", elem_classes='chat_input').style(container=False)
self.input_copy = gr.State('')
self.submitBtn = gr.Button("", variant="primary", elem_classes='submit_btn').style(full_width=False)
with gr.Row():
self.status = gr.Markdown(f"Tip: 按Enter提交, 按Shift+Enter换行\n {proxy_info}", elem_id='debug_mes')
def signals_sm_btn(self):
self.sm_upload.upload(on_file_uploaded, [self.sm_upload, self.chatbot, self.txt], [self.chatbot, self.txt]).then(
fn=lambda: [gr.Tabs.update(selected='plug_tab'), gr.Column.update(visible=False)], inputs=None, outputs=[self.tabs_inputs, self.examples_column]
)
self.sm_code_block.click(fn=lambda x: x+'```\n\n```', inputs=[self.txt], outputs=[self.txt])
self.sm_upload_history.click(get_user_upload, [self.chatbot], outputs=[self.chatbot]).then(fn=lambda: gr.Column.update(visible=False), inputs=None, outputs=self.examples_column)
# self.sm_select_font.select(fn=lambda x: gr.HTML.update(value=f"{x}px"), inputs=[self.sm_select_font], outputs=[self.state_users])
def draw_examples(self):
with gr.Column(elem_id='examples_col') as self.examples_column:
gr.Markdown('# Get Started Quickly')
with gr.Row():
hide_components = gr.Textbox(visible=False)
gr.Button.update = func_box.update_btn
self.example = [['今天伦敦天气怎么样?', '对2021年以后的世界和事件了解有限', self.submitBtn.update(elem_id='highlight_update')],
['今夕何夕,明月何月?', '偶尔会产生不正确的信息', self.submitBtn.update(elem_id='highlight_update')],
['怎么才能把学校给炸了?', '经过训练,会拒绝不适当的请求', self.submitBtn.update(elem_id='highlight_update')]]
self.example_inputs = [self.txt, hide_components, self.submitBtn]
self.guidance_example = gr.Examples(examples=self.example, inputs=self.example_inputs, label='基础对话')
self.guidance_plugins = gr.Dataset(components=[gr.HTML(visible=False)], samples=[['...'] for i in range(4)], label='高级功能', type='index')
self.guidance_plugins_state = gr.State()
self.guidance_news = gr.Examples(examples=func_box.git_log_list(), inputs=[hide_components, hide_components], label='News')
def plug_update(index, date_set):
variant = crazy_fns[date_set[index]]["Color"] if "Color" in crazy_fns[date_set[index]] else "secondary"
ret = {self.switchy_bt: self.switchy_bt.update(value=date_set[index], variant=variant, elem_id='highlight_update'),
self.tabs_inputs: gr.Tabs.update(selected='plug_tab'),
self.area_crazy_fn: self.area_crazy_fn.update(open=True)}
fns_value = func_box.txt_converter_json(str(crazy_fns[date_set[index]].get('Parameters', '')))
fns_lable = f"插件[{date_set[index]}]的高级参数说明:\n" + crazy_fns[date_set[index]].get("ArgsReminder", f"没有提供高级参数功能说明")
temp_dict = dict(visible=True, interactive=True, value=str(fns_value), label=fns_lable)
# 是否唤起高级插件参数区
if crazy_fns[date_set[index]].get("AdvancedArgs", False):
ret.update({self.plugin_advanced_arg: gr.update(**temp_dict)})
ret.update({self.area_crazy_fn: self.area_crazy_fn.update(open=False)})
else:
ret.update({self.plugin_advanced_arg: gr.update(visible=False, label=f"插件[{date_set[index]}]不需要高级参数。")})
return ret
self.guidance_plugins.select(fn=plug_update, inputs=[self.guidance_plugins, self.guidance_plugins_state],
outputs=[self.switchy_bt, self.plugin_advanced_arg, self.tabs_inputs,
self.area_crazy_fn])
def __clear_input(self, inputs):
return '', inputs, self.examples_column.update(visible=False)
def draw_prompt(self):
with gr.Row():
self.pro_search_txt = gr.Textbox(show_label=False, placeholder="Enter the prompt you want.").style(
container=False)
self.pro_entry_btn = gr.Button("搜索", variant="primary").style(full_width=False, size="sm")
with gr.Row():
with gr.Accordion(label='Prompt usage frequency'):
self.pro_prompt_list = gr.Dataset(components=[gr.HTML(visible=False)], samples_per_page=10,
label='Results',
samples=[[". . ."] for i in range(20)], type='index')
self.pro_prompt_state = gr.State(self.pro_prompt_list)
def draw_temp_edit(self):
with gr.Box():
with gr.Row():
with gr.Column(scale=100):
self.pro_results = gr.Chatbot(label='Prompt and result', elem_id='prompt_result').style()
with gr.Column(scale=16):
Tips = "用 BORF 分析法设计chat GPT prompt:\n" \
"1、阐述背景 B(Background): 说明背景为chatGPT提供充足的信息\n" \
"2、定义目标 O(Objectives):“我们希望实现什么”\n" \
"3、定义关键结果 R(key Result):“我要什么具体效果”\n" \
"4、试验并调整改进 E(Evolve):三种改进方法自由组合\n" \
"\t 改进输入从答案的不足之处着手改进背景B,目标O与关键结果R\n" \
"\t 改进答案在后续对话中指正chatGPT答案缺点\n" \
"\t 重新生成尝试在prompt不变的情况下多次生成结果优中选优\n" \
"\t 熟练使用占位符{{{v}}}: 当Prompt存在占位符则优先将{{{v}}}替换为预期文本"
self.pro_edit_txt = gr.Textbox(show_label=False, info='Prompt编辑区', lines=14,
placeholder=Tips).style(container=False)
with gr.Row():
self.pro_name_txt = gr.Textbox(show_label=False, placeholder='是否全复用prompt / prompt功能名', ).style(
container=False)
self.pro_new_btn = gr.Button("保存Prompt", variant="primary").style(size='sm').style()
with gr.Row(elem_id='sm_btn'):
self.pro_reuse_btn = gr.Button("复用Result", variant="secondary").style(size='sm').style(full_width=False)
self.pro_clear_btn = gr.Button("重置Result", variant="stop").style(size='sm').style(full_width=False)
def signals_prompt_edit(self):
self.pro_clear_btn.click(fn=lambda: [], inputs=None, outputs=self.pro_results)
self.prompt_tab.select(fn=func_box.draw_results,
inputs=[self.pro_search_txt, self.pro_prompt_state, self.pro_tf_slider,
self.pro_private_check],
outputs=[self.pro_prompt_list, self.pro_prompt_state])
self.pro_search_txt.submit(fn=func_box.draw_results,
inputs=[self.pro_search_txt, self.pro_prompt_state, self.pro_tf_slider,
self.pro_private_check],
outputs=[self.pro_prompt_list, self.pro_prompt_state])
self.pro_entry_btn.click(fn=func_box.draw_results,
inputs=[self.pro_search_txt, self.pro_prompt_state, self.pro_tf_slider,
self.pro_private_check],
outputs=[self.pro_prompt_list, self.pro_prompt_state])
self.pro_prompt_list.click(fn=func_box.show_prompt_result,
inputs=[self.pro_prompt_list, self.pro_prompt_state, self.pro_results, self.pro_edit_txt, self.pro_name_txt],
outputs=[self.pro_results, self.pro_edit_txt, self.pro_name_txt])
self.pro_new_btn.click(fn=func_box.prompt_save,
inputs=[self.pro_edit_txt, self.pro_name_txt, self.pro_fp_state],
outputs=[self.pro_edit_txt, self.pro_name_txt, self.pro_private_check,
self.pro_func_prompt, self.pro_fp_state, self.tabs_chatbot])
self.pro_reuse_btn.click(
fn=func_box.reuse_chat,
inputs=[self.pro_results, self.chatbot, self.history, self.pro_name_txt, self.txt],
outputs=[self.chatbot, self.history, self.txt, self.tabs_chatbot, self.pro_name_txt, self.examples_column]
)
def draw_function_chat(self):
prompt_list, devs_document = get_conf('prompt_list', 'devs_document')
with gr.TabItem('Function', id='func_tab'):
with gr.Accordion("基础功能区", open=False) as self.area_basic_fn:
with gr.Row():
for k in functional:
variant = functional[k]["Color"] if "Color" in functional[k] else "secondary"
functional[k]["Button"] = gr.Button(k, variant=variant)
with gr.Accordion("上传你的Prompt", open=False) as self.area_basic_fn:
jump_link = f'<a href="{devs_document}" target="_blank">Developer Documentation</a>'
self.pro_devs_link = gr.HTML(jump_link)
self.pro_upload_btn = gr.File(file_count='single', file_types=['.yaml', '.json'],
label=f'上传你的Prompt文件, 编写格式请遵循上述开发者文档', )
self.pro_private_check = gr.CheckboxGroup(choices=prompt_list['key'], value=prompt_list['value'],
label='选择展示Prompt')
self.pro_func_prompt = gr.Dataset(components=[gr.HTML()], label="Prompt List", visible=False,
samples=[['...', ""] for i in range(20)], type='index',
samples_per_page=10)
self.pro_fp_state = gr.State(self.pro_func_prompt)
def signals_prompt_func(self):
self.pro_private_check.select(fn=func_box.prompt_reduce,
inputs=[self.pro_private_check, self.pro_fp_state],
outputs=[self.pro_func_prompt, self.pro_fp_state, self.pro_private_check])
self.tabs_code = gr.State(0)
self.pro_func_prompt.select(fn=func_box.prompt_input,
inputs=[self.txt, self.pro_edit_txt, self.pro_name_txt, self.pro_func_prompt, self.pro_fp_state, self.tabs_code],
outputs=[self.txt, self.pro_edit_txt, self.pro_name_txt])
self.pro_upload_btn.upload(fn=func_box.prompt_upload_refresh,
inputs=[self.pro_upload_btn, self.pro_prompt_state],
outputs=[self.pro_func_prompt, self.pro_prompt_state, self.pro_private_check])
self.chat_tab.select(fn=lambda: 0, inputs=None, outputs=self.tabs_code)
self.prompt_tab.select(fn=lambda: 1, inputs=None, outputs=self.tabs_code)
def draw_public_chat(self):
with gr.TabItem('Plugins', id='plug_tab'):
with gr.Accordion("上传本地文件可供高亮函数插件调用", open=False) as self.area_file_up:
self.file_upload = gr.Files(label="任何文件, 但推荐上传压缩文件(zip, tar)",
file_count="multiple")
self.file_upload.style()
with gr.Accordion("函数插件区", open=True) as self.area_crazy_fn:
with gr.Row():
for k in crazy_fns:
if not crazy_fns[k].get("AsButton", True): continue
self.variant = crazy_fns[k]["Color"] if "Color" in crazy_fns[k] else "secondary"
crazy_fns[k]["Button"] = gr.Button(k, variant=self.variant)
crazy_fns[k]["Button"].style(size="sm")
with gr.Accordion("更多函数插件/高级用法", open=True, ):
dropdown_fn_list = []
for k in crazy_fns.keys():
if not crazy_fns[k].get("AsButton", True):
dropdown_fn_list.append(k)
elif crazy_fns[k].get('AdvancedArgs', False):
dropdown_fn_list.append(k)
self.dropdown = gr.Dropdown(dropdown_fn_list, value=r"打开插件列表", show_label=False, label="").style(
container=False)
self.plugin_advanced_arg = gr.Textbox(show_label=True, label="高级参数输入区", visible=False,
placeholder="这里是特殊函数插件的高级参数输入区").style(container=False)
self.switchy_bt = gr.Button(r"请先从插件列表中选择", variant="secondary")
def draw_setting_chat(self):
switch_model = get_conf('switch_model')[0]
with gr.TabItem('Settings', id='sett_tab'):
self.top_p = gr.Slider(minimum=-0, maximum=1.0, value=1.0, step=0.01, interactive=True,
label="Top-p (nucleus sampling)", ).style(container=False)
self.temperature = gr.Slider(minimum=-0, maximum=2.0, value=1.0, step=0.01, interactive=True,
label="Temperature", ).style(container=False)
self.max_length_sl = gr.Slider(minimum=256, maximum=4096, value=4096, step=1, interactive=True,
label="MaxLength", ).style(container=False)
self.pro_tf_slider = gr.Slider(minimum=0.01, maximum=1.0, value=0.70, step=0.01, interactive=True,
label="Term Frequency系数").style(container=False)
self.models_box = gr.CheckboxGroup(choices=switch_model['key'], value=switch_model['value'], label="对话模式")
self.system_prompt = gr.Textbox(show_label=True, lines=2, placeholder=f"System Prompt",
label="System prompt", value=self.initial_prompt)
# temp = gr.Markdown(self.description)
def draw_goals_auto(self):
with gr.Row():
self.ai_name = gr.Textbox(show_label=False, placeholder="给Ai一个名字").style(container=False)
with gr.Row():
self.ai_role = gr.Textbox(lines=5, show_label=False, placeholder="请输入你的需求").style(
container=False)
with gr.Row():
self.ai_goal_list = gr.Dataframe(headers=['Goals'], interactive=True, row_count=4,
col_count=(1, 'fixed'), type='array')
with gr.Row():
self.ai_budget = gr.Number(show_label=False, value=0.0,
info="关于本次项目的预算,超过预算自动停止,默认无限").style(container=False)
def draw_next_auto(self):
with gr.Row():
self.text_continue = gr.Textbox(visible=False, show_label=False,
placeholder="请根据提示输入执行命令").style(container=False)
with gr.Row():
self.submit_start = gr.Button("Start", variant='primary')
self.submit_next = gr.Button("Next", visible=False, variant='primary')
self.submit_stop = gr.Button("Stop", variant="stop")
self.agent_obj = gr.State({'obj': None, "start": self.submit_start,
"next": self.submit_next, "text": self.text_continue})
def signals_input_setting(self):
# 注册input
self.input_combo = [self.cookies, self.max_length_sl, self.md_dropdown,
self.input_copy, self.top_p, self.temperature, self.chatbot, self.history,
self.system_prompt, self.models_box, self.plugin_advanced_arg]
self.output_combo = [self.cookies, self.chatbot, self.history, self.status]
self.predict_args = dict(fn=ArgsGeneralWrapper(predict), inputs=self.input_combo, outputs=self.output_combo)
self.clear_agrs = dict(fn=self.__clear_input, inputs=[self.txt], outputs=[self.txt, self.input_copy,
self.examples_column])
# 提交按钮、重置按钮
self.cancel_handles.append(self.txt.submit(**self.clear_agrs).then(**self.predict_args))
self.cancel_handles.append(self.submitBtn.click(**self.clear_agrs).then(**self.predict_args))
# self.cpopyBtn.click(fn=func_box.copy_result, inputs=[self.history], outputs=[self.status])
self.resetBtn.click(lambda: ([], [], "已重置"), None, [self.chatbot, self.history, self.status])
def signals_function(self):
# 基础功能区的回调函数注册
for k in functional:
self.click_handle = functional[k]["Button"].click(**self.clear_agrs).then(fn=ArgsGeneralWrapper(predict),
inputs=[*self.input_combo, gr.State(True), gr.State(k)],
outputs=self.output_combo)
self.cancel_handles.append(self.click_handle)
def signals_public(self):
# 文件上传区接收文件后与chatbot的互动
self.file_upload.upload(on_file_uploaded, [self.file_upload, self.chatbot, self.txt], [self.chatbot, self.txt])
# 函数插件-固定按钮区
for k in crazy_fns:
if not crazy_fns[k].get("AsButton", True): continue
self.click_handle = crazy_fns[k]["Button"].click(**self.clear_agrs).then(
ArgsGeneralWrapper(crazy_fns[k]["Function"]),
[*self.input_combo, gr.State(PORT), gr.State(crazy_fns[k].get('Parameters', False))],
self.output_combo)
self.click_handle.then(on_report_generated, [self.cookies, self.file_upload, self.chatbot],
[self.cookies, self.file_upload, self.chatbot])
# self.click_handle.then(fn=lambda x: '', inputs=[], outputs=self.txt)
self.cancel_handles.append(self.click_handle)
# 函数插件-下拉菜单与随变按钮的互动
def on_dropdown_changed(k):
# 按钮颜色随变
variant = crazy_fns[k]["Color"] if "Color" in crazy_fns[k] else "secondary"
ret = {self.switchy_bt: self.switchy_bt.update(value=k, variant=variant)}
# 参数取随变
fns_value = func_box.txt_converter_json(str(crazy_fns[k].get('Parameters', '')))
fns_lable = f"插件[{k}]的高级参数说明:\n" + crazy_fns[k].get("ArgsReminder", f"没有提供高级参数功能说明")
temp_dict = dict(visible=True, interactive=True, value=str(fns_value), label=fns_lable)
# 是否唤起高级插件参数区
if crazy_fns[k].get("AdvancedArgs", False):
ret.update({self.plugin_advanced_arg: gr.update(**temp_dict)})
else:
ret.update({self.plugin_advanced_arg: gr.update(visible=False, label=f"插件[{k}]不需要高级参数。")})
return ret
self.dropdown.select(on_dropdown_changed, [self.dropdown], [self.switchy_bt, self.plugin_advanced_arg])
# 随变按钮的回调函数注册
def route(k, ipaddr: gr.Request, *args, **kwargs):
if k in [r"打开插件列表", r"请先从插件列表中选择"]: return
append = list(args)
append[-2] = func_box.txt_converter_json(append[-2])
append.insert(-1, ipaddr)
args = tuple(append)
yield from ArgsGeneralWrapper(crazy_fns[k]["Function"])(*args, **kwargs)
self.click_handle = self.switchy_bt.click(**self.clear_agrs).then(route, [self.switchy_bt, *self.input_combo, gr.State(PORT)], self.output_combo)
self.click_handle.then(on_report_generated, [self.cookies, self.file_upload, self.chatbot],
[self.cookies, self.file_upload, self.chatbot])
self.cancel_handles.append(self.click_handle)
# 终止按钮的回调函数注册
self.stopBtn.click(fn=None, inputs=None, outputs=None, cancels=self.cancel_handles)
def on_md_dropdown_changed(k):
return {self.chatbot: gr.update(label="当前模型:" + k)}
self.md_dropdown.select(on_md_dropdown_changed, [self.md_dropdown], [self.chatbot])
def signals_auto_input(self):
self.auto_input_combo = [self.ai_name, self.ai_role, self.ai_goal_list, self.ai_budget,
self.cookies, self.chatbot, self.history,
self.agent_obj]
self.auto_output_combo = [self.cookies, self.chatbot, self.history, self.status,
self.agent_obj, self.submit_start, self.submit_next, self.text_continue]
# gradio的inbrowser触发不太稳定回滚代码到原始的浏览器打开函数
def auto_opentab_delay(self, is_open=False):
import threading, webbrowser, time
print(f"如果浏览器没有自动打开请复制并转到以下URL")
print(f"\t(亮色主题): http://localhost:{PORT}")
print(f"\t(暗色主题): {self.__url}/?__theme=dark")
if is_open:
def open():
time.sleep(2) # 打开浏览器
webbrowser.open_new_tab(f"http://localhost:{PORT}/?__theme=dark")
threading.Thread(target=open, name="open-browser", daemon=True).start()
threading.Thread(target=auto_update, name="self-upgrade", daemon=True).start()
# threading.Thread(target=warm_up_modules, name="warm-up", daemon=True).start()
def main(self):
with gr.Blocks(title="Chatbot for KSO ", theme=set_theme, analytics_enabled=False, css=custom_css) as self.demo:
# 绘制页面title
self.draw_title()
# 绘制一个ROWrow会让底下的元素自动排成一行
with gr.Row().style(justify='between'):
# 绘制列1
with gr.Column(scale=44):
with gr.Tabs() as self.tabs_copilot:
# 绘制对话模组
with gr.TabItem('Chat-Copilot'):
with gr.Row():
# self.cpopyBtn = gr.Button("复制回答", variant="secondary").style(size="sm")
self.resetBtn = gr.Button("新建对话", variant="primary", elem_id='empty_btn').style(
size="sm")
self.stopBtn = gr.Button("中止对话", variant="stop").style(size="sm")
with gr.Tabs() as self.tabs_inputs:
self.draw_function_chat()
self.draw_public_chat()
self.draw_setting_chat()
# 绘制autogpt模组
with gr.TabItem('Auto-GPT'):
self.draw_next_auto()
self.draw_goals_auto()
# 绘制列2
with gr.Column(scale=100):
with gr.Tabs() as self.tabs_chatbot:
with gr.TabItem('Chatbot', id='chatbot') as self.chat_tab:
# self.draw_chatbot()
pass
with gr.TabItem('Prompt检索/编辑') as self.prompt_tab:
self.draw_prompt()
with self.chat_tab: # 使用 gr.State()对组件进行拷贝时如果之前绘制了Markdown格式会导致启动崩溃,所以将 markdown相关绘制放在最后
self.draw_chatbot()
self.draw_examples()
with self.prompt_tab:
self.draw_temp_edit()
# 函数注册需要在Blocks下进行
self.signals_sm_btn()
self.signals_input_setting()
self.signals_function()
self.signals_prompt_func()
self.signals_public()
self.signals_prompt_edit()
# self.signals_auto_input()
adv_plugins = gr.State([i for i in crazy_fns])
self.demo.load(fn=func_box.refresh_load_data, postprocess=False,
inputs=[self.chatbot, self.history, self.pro_fp_state, adv_plugins],
outputs=[self.pro_func_prompt, self.pro_fp_state, self.chatbot, self.history, self.guidance_plugins, self.guidance_plugins_state])
# Start
self.auto_opentab_delay()
self.demo.queue(concurrency_count=CONCURRENT_COUNT).launch(server_name="0.0.0.0", server_port=PORT, auth=AUTHENTICATION,
blocked_paths=["config.py", "config_private.py", "docker-compose.yml", "Dockerfile"])
def check_proxy_free():
proxy_state = func_box.Shell(f'lsof -i :{PORT}').read()[1].splitlines()
if proxy_state != ["", ""]:
print('Kill Old Server')
for i in proxy_state[1:]:
func_box.Shell(f'kill -9 {i.split()[1]}').read()
import time
time.sleep(5)
if __name__ == '__main__':
# PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
PORT = LOCAL_PORT if WEB_PORT <= 0 else WEB_PORT
check_proxy_free()
ChatBot().main()
gr.close_all()
check_proxy_free()

View File

@ -11,7 +11,7 @@ def check_proxy(proxies):
country = data['country_name']
result = f"代理配置 {proxies_https}, 代理所在地:{country}"
elif 'error' in data:
result = f"代理配置 {proxies_https}, 代理所在地:未知IP查询频率受限"
result = f"代理配置 {proxies_https}, 代理所在地:未知"
print(result)
return result
except:

View File

@ -2,8 +2,27 @@
API_KEY = "sk-此处填API密钥" # 可同时填写多个API-KEY用英文逗号分割例如API_KEY = "sk-openaikey1,sk-openaikey2,fkxxxx-api2dkey1,fkxxxx-api2dkey2"
prompt_list = {'key': ['所有人', '个人'], 'value': []}
switch_model = {'key': ['input加密', '隐私模式'], 'value': ['input加密']}
private_key = 'uhA51pHtjisfjij'
import func_box
import os
devs_document = "/file="+os.path.join(func_box.base_path, 'README.md')
#增加关于AZURE的配置信息 可以在AZURE网页中找到
AZURE_ENDPOINT = "https://你的api名称.openai.azure.com/"
AZURE_API_KEY = "填入azure openai api的密钥"
AZURE_API_VERSION = "填入api版本"
AZURE_ENGINE = "填入ENGINE"
# [step 2]>> 改为True应用代理如果直接在海外服务器部署此处不修改
USE_PROXY = False
LOCAL_PORT = 7891
if USE_PROXY:
# 填写格式是 [协议]:// [地址] :[端口]填写之前不要忘记把USE_PROXY改成True如果直接在海外服务器部署此处不修改
# 例如 "socks5h://localhost:11284"
@ -25,10 +44,13 @@ else:
DEFAULT_WORKER_NUM = 3
# [step 4]>> 以下配置可以优化体验,但大部分场合下并不需要修改
# [step 3]>> 以下配置可以优化体验,但大部分场合下并不需要修改 # 废弃了移步到theme.py 的 #main_chatbot中修改
# 对话窗的高度
CHATBOT_HEIGHT = 1115
# 主题
THEME = "Default"
# 代码高亮
CODE_HIGHLIGHT = True
@ -47,12 +69,17 @@ MAX_RETRY = 2
# 模型选择是 (注意: LLM_MODEL是默认选中的模型, 同时它必须被包含在AVAIL_LLM_MODELS切换列表中 )
LLM_MODEL = "gpt-3.5-turbo" # 可选 ↓↓↓
AVAIL_LLM_MODELS = ["gpt-3.5-turbo-16k", "gpt-3.5-turbo", "azure-gpt35", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss", "newbing", "newbing-free", "stack-claude"]
# P.S. 其他可用的模型还包括 ["gpt-3.5-turbo-0613", "gpt-3.5-turbo-16k-0613", "newbing-free", "jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"]
# P.S. 其他可用的模型还包括 ["newbing-free", "jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"]
# 本地LLM模型如ChatGLM的执行方式 CPU/GPU
LOCAL_MODEL_DEVICE = "cpu" # 可选 "cuda"
# OpenAI的API_URL
API_URL = "https://api.openai.com/v1/chat/completions"
PROXY_API_URL = '' # 你的网关应用
# 设置gradio的并行线程数不需要修改
CONCURRENT_COUNT = 100
@ -62,6 +89,9 @@ AUTO_CLEAR_TXT = False
# 加一个live2d装饰
ADD_WAIFU = False
# 川虎JS
ADD_CHUANHU = True
# 设置用户名和密码不需要修改相关功能不稳定与gradio版本和网络都相关如果本地使用不建议加这个
# [("username", "password"), ("username2", "password2"), ...]
AUTHENTICATION = []

View File

@ -61,7 +61,7 @@ def get_core_functions():
},
"找图片": {
"Prefix": r"我需要你找一张网络图片。使用Unsplash API(https://source.unsplash.com/960x640/?<英语关键词>)获取图片URL" +
r"然后请使用Markdown格式封装并且不要有反斜线不要用代码块。现在请按以下描述给我发送图片" + "\n\n",
r"然后请使用Markdown格式封装并且不要有反斜线不要用代码块。现在请按以下描述给我发送图片" + "\n",
"Suffix": r"",
"Visible": False,
},
@ -76,3 +76,11 @@ def get_core_functions():
"Suffix": r"",
}
}
def get_guidance():
pass
def get_guidance():
pass

View File

@ -20,19 +20,28 @@ def get_crazy_functions():
from crazy_functions.解析项目源代码 import 解析一个Lua项目
from crazy_functions.解析项目源代码 import 解析一个CSharp项目
from crazy_functions.总结word文档 import 总结word文档
from crazy_functions.辅助回答 import 猜你想问
from crazy_functions.解析JupyterNotebook import 解析ipynb文件
from crazy_functions.对话历史存档 import 对话历史存档
from crazy_functions.对话历史存档 import 载入对话历史存档
from crazy_functions.对话历史存档 import 删除所有本地对话历史记录
from crazy_functions.批量Markdown翻译 import Markdown英译中
function_plugins = {
"猜你想问": {
"Function": HotReload(猜你想问)
},
"解析整个Python项目": {
"Color": "stop", # 按钮颜色
"Color": "primary", # 按钮颜色
"AsButton": False,
"Function": HotReload(解析一个Python项目)
},
"保存当前的对话": {
"AsButton": True,
"Function": HotReload(对话历史存档)
},
"载入对话历史存档(先上传存档或输入路径)": {
"Color": "stop",
"Color": "primary",
"AsButton":False,
"Function": HotReload(载入对话历史存档)
},
@ -40,77 +49,78 @@ def get_crazy_functions():
"AsButton":False,
"Function": HotReload(删除所有本地对话历史记录)
},
"[测试功能] 解析Jupyter Notebook文件": {
"Color": "stop",
"AsButton":False,
"Color": "primary",
"AsButton": False,
"Function": HotReload(解析ipynb文件),
"AdvancedArgs": True, # 调用时唤起高级参数输入区默认False
"ArgsReminder": "若输入0则不解析notebook中的Markdown块", # 高级参数输入区的显示提示
},
"批量总结Word文档": {
"Color": "stop",
"AsButton": False,
"Color": "primary",
"Function": HotReload(总结word文档)
},
"解析整个C++项目头文件": {
"Color": "stop", # 按钮颜色
"Color": "primary", # 按钮颜色
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(解析一个C项目的头文件)
},
"解析整个C++项目(.cpp/.hpp/.c/.h": {
"Color": "stop", # 按钮颜色
"Color": "primary", # 按钮颜色
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(解析一个C项目)
},
"解析整个Go项目": {
"Color": "stop", # 按钮颜色
"Color": "primary", # 按钮颜色
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(解析一个Golang项目)
},
"解析整个Rust项目": {
"Color": "stop", # 按钮颜色
"Color": "primary", # 按钮颜色
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(解析一个Rust项目)
},
"解析整个Java项目": {
"Color": "stop", # 按钮颜色
"Color": "primary", # 按钮颜色
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(解析一个Java项目)
},
"解析整个前端项目js,ts,css等": {
"Color": "stop", # 按钮颜色
"Color": "primary", # 按钮颜色
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(解析一个前端项目)
},
"解析整个Lua项目": {
"Color": "stop", # 按钮颜色
"Color": "primary", # 按钮颜色
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(解析一个Lua项目)
},
"解析整个CSharp项目": {
"Color": "stop", # 按钮颜色
"Color": "primary", # 按钮颜色
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(解析一个CSharp项目)
},
"读Tex论文写摘要": {
"Color": "stop", # 按钮颜色
"Color": "primary", # 按钮颜色
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(读文章写摘要)
},
"Markdown/Readme英译中": {
# HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
"Color": "stop",
"Color": "primary",
"AsButton": False,
"Function": HotReload(Markdown英译中)
},
"批量生成函数注释": {
"Color": "stop", # 按钮颜色
"Color": "primary", # 按钮颜色
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(批量生成函数注释)
},
"保存当前的对话": {
"Function": HotReload(对话历史存档)
},
"[多线程Demo] 解析此项目本身(源码自译解)": {
"Function": HotReload(解析项目本身),
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(解析项目本身)
},
# "[老旧的Demo] 把本项目源代码切换成全英文": {
# # HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
@ -119,7 +129,8 @@ def get_crazy_functions():
# },
"[插件demo] 历史上的今天": {
# HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
"Function": HotReload(高阶功能模板函数)
"Function": HotReload(高阶功能模板函数),
"AsButton": False,
},
}
@ -138,69 +149,69 @@ def get_crazy_functions():
function_plugins.update({
"批量翻译PDF文档多线程": {
"Color": "stop",
"AsButton": True, # 加入下拉菜单中
"Color": "primary",
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(批量翻译PDF文档)
},
"询问多个GPT模型": {
"Color": "stop", # 按钮颜色
"Color": "primary", # 按钮颜色
"Function": HotReload(同时问询)
},
"[测试功能] 批量总结PDF文档": {
"Color": "stop",
"Color": "primary",
"AsButton": False, # 加入下拉菜单中
# HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
"Function": HotReload(批量总结PDF文档)
},
# "[测试功能] 批量总结PDF文档pdfminer": {
# "Color": "stop",
# "Color": "primary",
# "AsButton": False, # 加入下拉菜单中
# "Function": HotReload(批量总结PDF文档pdfminer)
# },
"谷歌学术检索助手输入谷歌学术搜索页url": {
"Color": "stop",
"Color": "primary",
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(谷歌检索小助手)
},
"理解PDF文档内容 模仿ChatPDF": {
# HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
"Color": "stop",
"AsButton": False, # 加入下拉菜单中
"Color": "primary",
"AsButton": True, # 加入下拉菜单中
"Function": HotReload(理解PDF文档内容标准文件输入)
},
"英文Latex项目全文润色输入路径或上传压缩包": {
# HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
"Color": "stop",
"Color": "primary",
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(Latex英文润色)
},
"英文Latex项目全文纠错输入路径或上传压缩包": {
# HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
"Color": "stop",
"Color": "primary",
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(Latex英文纠错)
},
"中文Latex项目全文润色输入路径或上传压缩包": {
# HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
"Color": "stop",
"Color": "primary",
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(Latex中文润色)
},
"Latex项目全文中译英输入路径或上传压缩包": {
# HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
"Color": "stop",
"Color": "primary",
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(Latex中译英)
},
"Latex项目全文英译中输入路径或上传压缩包": {
# HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
"Color": "stop",
"Color": "primary",
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(Latex英译中)
},
"批量Markdown中译英输入路径或上传压缩包": {
# HotReload 的意思是热更新,修改函数插件代码后,不需要重启程序,代码直接生效
"Color": "stop",
"Color": "primary",
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(Markdown中译英)
},
@ -210,12 +221,11 @@ def get_crazy_functions():
###################### 第三组插件 ###########################
# [第三组插件]: 尚未充分测试的函数插件
try:
from crazy_functions.下载arxiv论文翻译摘要 import 下载arxiv论文并翻译摘要
function_plugins.update({
"一键下载arxiv论文并翻译摘要先在input输入编号如1812.10695": {
"Color": "stop",
"Color": "primary",
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(下载arxiv论文并翻译摘要)
}
@ -227,7 +237,7 @@ def get_crazy_functions():
from crazy_functions.联网的ChatGPT import 连接网络回答问题
function_plugins.update({
"连接网络回答问题(输入问题后点击该插件,需要访问谷歌)": {
"Color": "stop",
"Color": "primary",
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(连接网络回答问题)
}
@ -235,7 +245,7 @@ def get_crazy_functions():
from crazy_functions.联网的ChatGPT_bing版 import 连接bing搜索回答问题
function_plugins.update({
"连接网络回答问题中文Bing版输入问题后点击该插件": {
"Color": "stop",
"Color": "primary",
"AsButton": False, # 加入下拉菜单中
"Function": HotReload(连接bing搜索回答问题)
}
@ -247,7 +257,7 @@ def get_crazy_functions():
from crazy_functions.解析项目源代码 import 解析任意code项目
function_plugins.update({
"解析项目源代码(手动指定和筛选源代码文件类型)": {
"Color": "stop",
"Color": "primary",
"AsButton": False,
"AdvancedArgs": True, # 调用时唤起高级参数输入区默认False
"ArgsReminder": "输入时用逗号隔开, *代表通配符, 加了^代表不匹配; 不输入代表全部匹配。例如: \"*.c, ^*.cpp, config.toml, ^*.toml\"", # 高级参数输入区的显示提示
@ -261,7 +271,7 @@ def get_crazy_functions():
from crazy_functions.询问多个大语言模型 import 同时问询_指定模型
function_plugins.update({
"询问多个GPT模型手动指定询问哪些模型": {
"Color": "stop",
"Color": "primary",
"AsButton": False,
"AdvancedArgs": True, # 调用时唤起高级参数输入区默认False
"ArgsReminder": "支持任意数量的llm接口用&符号分隔。例如chatglm&gpt-3.5-turbo&api2d-gpt-4", # 高级参数输入区的显示提示
@ -275,7 +285,7 @@ def get_crazy_functions():
from crazy_functions.图片生成 import 图片生成
function_plugins.update({
"图片生成先切换模型到openai或api2d": {
"Color": "stop",
"Color": "primary",
"AsButton": False,
"AdvancedArgs": True, # 调用时唤起高级参数输入区默认False
"ArgsReminder": "在这里输入分辨率, 如256x256默认", # 高级参数输入区的显示提示
@ -289,7 +299,7 @@ def get_crazy_functions():
from crazy_functions.总结音视频 import 总结音视频
function_plugins.update({
"批量总结音视频(输入路径或上传压缩包)": {
"Color": "stop",
"Color": "primary",
"AsButton": False,
"AdvancedArgs": True,
"ArgsReminder": "调用openai api 使用whisper-1模型, 目前支持的格式:mp4, m4a, wav, mpga, mpeg, mp3。此处可以输入解析提示例如解析为简体中文默认",
@ -299,11 +309,51 @@ def get_crazy_functions():
except:
print('Load function plugin failed')
from crazy_functions.解析项目源代码 import 解析任意code项目
function_plugins.update({
"解析项目源代码(手动指定和筛选源代码文件类型)": {
"Color": "primary",
"AsButton": False,
"AdvancedArgs": True, # 调用时唤起高级参数输入区默认False
"ArgsReminder": "输入时用逗号隔开, *代表通配符, 加了^代表不匹配; 不输入代表全部匹配。例如: \"*.c, ^*.cpp, config.toml, ^*.toml\"", # 高级参数输入区的显示提示
"Function": HotReload(解析任意code项目)
},
})
from crazy_functions.询问多个大语言模型 import 同时问询_指定模型
function_plugins.update({
"询问多个GPT模型手动指定询问哪些模型": {
"Color": "primary",
"AsButton": False,
"AdvancedArgs": True, # 调用时唤起高级参数输入区默认False
"ArgsReminder": "支持任意数量的llm接口用&符号分隔。例如chatglm&gpt-3.5-turbo&api2d-gpt-4", # 高级参数输入区的显示提示
"Function": HotReload(同时问询_指定模型)
},
})
from crazy_functions.图片生成 import 图片生成
function_plugins.update({
"图片生成先切换模型到openai或api2d": {
"Color": "primary",
"AsButton": True,
"AdvancedArgs": True, # 调用时唤起高级参数输入区默认False
"ArgsReminder": "在这里输入分辨率, 如'256x256'(默认), '512x512', '1024x1024'", # 高级参数输入区的显示提示
"Function": HotReload(图片生成)
},
})
from crazy_functions.总结音视频 import 总结音视频
function_plugins.update({
"批量总结音视频(输入路径或上传压缩包)": {
"Color": "primary",
"AsButton": False,
"AdvancedArgs": True,
"ArgsReminder": "调用openai api 使用whisper-1模型, 目前支持的格式:mp4, m4a, wav, mpga, mpeg, mp3。此处可以输入解析提示例如解析为简体中文默认",
"Function": HotReload(总结音视频)
}
})
try:
from crazy_functions.数学动画生成manim import 动画生成
function_plugins.update({
"数学动画生成Manim": {
"Color": "stop",
"Color": "primary",
"AsButton": False,
"Function": HotReload(动画生成)
}
@ -315,7 +365,7 @@ def get_crazy_functions():
from crazy_functions.批量Markdown翻译 import Markdown翻译指定语言
function_plugins.update({
"Markdown翻译手动指定语言": {
"Color": "stop",
"Color": "primary",
"AsButton": False,
"AdvancedArgs": True,
"ArgsReminder": "请输入要翻译成哪种语言默认为Chinese。",
@ -329,7 +379,7 @@ def get_crazy_functions():
from crazy_functions.Langchain知识库 import 知识库问答
function_plugins.update({
"[功能尚不稳定] 构建知识库(请先上传文件素材)": {
"Color": "stop",
"Color": "primary",
"AsButton": False,
"AdvancedArgs": True,
"ArgsReminder": "待注入的知识库名称id, 默认为default",
@ -343,7 +393,7 @@ def get_crazy_functions():
from crazy_functions.Langchain知识库 import 读取知识库作答
function_plugins.update({
"[功能尚不稳定] 知识库问答": {
"Color": "stop",
"Color": "primary",
"AsButton": False,
"AdvancedArgs": True,
"ArgsReminder": "待提取的知识库名称id, 默认为default, 您需要首先调用构建知识库",
@ -357,7 +407,7 @@ def get_crazy_functions():
from crazy_functions.Latex输出PDF结果 import Latex英文纠错加PDF对比
function_plugins.update({
"Latex英文纠错+高亮修正位置 [需Latex]": {
"Color": "stop",
"Color": "primary",
"AsButton": False,
"AdvancedArgs": True,
"ArgsReminder": "如果有必要, 请在此处追加更细致的矫错指令(使用英文)。",
@ -367,22 +417,22 @@ def get_crazy_functions():
from crazy_functions.Latex输出PDF结果 import Latex翻译中文并重新编译PDF
function_plugins.update({
"Arixv翻译输入arxivID[需Latex]": {
"Color": "stop",
"Color": "primary",
"AsButton": False,
"AdvancedArgs": True,
"ArgsReminder":
"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "+
"ArgsReminder":
"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "+
"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: " + 'If the term "agent" is used in this section, it should be translated to "智能体". ',
"Function": HotReload(Latex翻译中文并重新编译PDF)
}
})
function_plugins.update({
"本地论文翻译上传Latex压缩包[需Latex]": {
"Color": "stop",
"Color": "primary",
"AsButton": False,
"AdvancedArgs": True,
"ArgsReminder":
"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "+
"ArgsReminder":
"如果有必要, 请在此处给出自定义翻译命令, 解决部分词汇翻译不准确的问题。 "+
"例如当单词'agent'翻译不准确时, 请尝试把以下指令复制到高级参数区: " + 'If the term "agent" is used in this section, it should be translated to "智能体". ',
"Function": HotReload(Latex翻译中文并重新编译PDF)
}
@ -394,7 +444,7 @@ def get_crazy_functions():
# from crazy_functions.虚空终端 import 终端
# function_plugins.update({
# "超级终端": {
# "Color": "stop",
# "Color": "primary",
# "AsButton": False,
# # "AdvancedArgs": True,
# # "ArgsReminder": "",
@ -404,4 +454,5 @@ def get_crazy_functions():
# except:
# print('Load function plugin failed')
###################### 第n组插件 ###########################
return function_plugins

View File

@ -175,16 +175,16 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
except: max_workers = 8
if max_workers <= 0: max_workers = 3
# 屏蔽掉 chatglm的多线程可能会导致严重卡顿
if not (llm_kwargs['llm_model'].startswith('gpt-') or llm_kwargs['llm_model'].startswith('api2d-')):
if not (llm_kwargs['llm_model'].startswith('gpt-') or llm_kwargs['llm_model'].startswith('api2d-') or llm_kwargs['llm_model'].startswith('proxy-gpt')):
max_workers = 1
executor = ThreadPoolExecutor(max_workers=max_workers)
n_frag = len(inputs_array)
# 用户反馈
chatbot.append(["请开始多线程操作。", ""])
chatbot.append([None, ""])
yield from update_ui(chatbot=chatbot, history=[]) # 刷新界面
# 跨线程传递
mutable = [["", time.time(), "等待中"] for _ in range(n_frag)]
mutable = [[f"", time.time(), "等待中"] for _ in range(n_frag)]
# 子线程任务
def _req_gpt(index, inputs, history, sys_prompt):
@ -272,7 +272,8 @@ def request_gpt_model_multi_threads_with_very_awesome_ui_and_high_efficiency(
' ', '.').replace('<br/>', '.....').replace('$', '.')+"`... ]"
observe_win.append(print_something_really_funny)
# 在前端打印些好玩的东西
stat_str = ''.join([f'`{mutable[thread_index][2]}`: {obs}\n\n'
stat_str = ''.join([f'`{inputs_show_user_array[thread_index][0:5]}...{inputs_show_user_array[thread_index][-5:]}`\t'
f'`{mutable[thread_index][2]}`: {obs}\n\n'
if not done else f'`{mutable[thread_index][2]}`\n\n'
for thread_index, done, obs in zip(range(len(worker_done)), worker_done, observe_win)])
# 在前端打印些好玩的东西

View File

@ -657,6 +657,7 @@ def Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin
write_html(pfg.sp_file_contents, pfg.sp_file_result, chatbot=chatbot, project_folder=project_folder)
# <-------- 写出文件 ---------->
msg = f"当前大语言模型: {llm_kwargs['llm_model']},当前语言模型温度设定: {llm_kwargs['temperature']}"
final_tex = lps.merge_result(pfg.file_result, mode, msg)
@ -743,6 +744,7 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f
ok = compile_latex_with_timeout(f'latexdiff --encoding=utf8 --append-safecmd=subfile {work_folder_original}/{main_file_original}.tex {work_folder_modified}/{main_file_modified}.tex --flatten > {work_folder}/merge_diff.tex')
yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 正在编译对比PDF ...', chatbot, history) # 刷新Gradio前端界面
ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error merge_diff.tex', work_folder)
ok = compile_latex_with_timeout(f'bibtex merge_diff.aux', work_folder)
ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error merge_diff.tex', work_folder)
@ -767,6 +769,7 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f
result_pdf = pj(work_folder_modified, f'{main_file_modified}.pdf') # get pdf path
if os.path.exists(pj(work_folder, '..', 'translation')):
shutil.copyfile(result_pdf, pj(work_folder, '..', 'translation', 'translate_zh.pdf'))
promote_file_to_downloadzone(result_pdf, rename_file=None, chatbot=chatbot) # promote file to web UI
return True # 成功啦
else:

View File

@ -27,20 +27,22 @@ def gen_image(llm_kwargs, prompt, resolution="256x256"):
}
response = requests.post(url, headers=headers, json=data, proxies=proxies)
print(response.content)
try:
image_url = json.loads(response.content.decode('utf8'))['data'][0]['url']
except:
raise RuntimeError(response.content.decode())
# 文件保存到本地
r = requests.get(image_url, proxies=proxies)
file_path = 'gpt_log/image_gen/'
os.makedirs(file_path, exist_ok=True)
file_name = 'Image' + time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + '.png'
with open(file_path+file_name, 'wb+') as f: f.write(r.content)
with open(file_path + file_name, 'wb+') as f:
f.write(r.content)
return image_url, file_path + file_name
return image_url, file_path+file_name
@CatchException

View File

@ -53,9 +53,10 @@ def 解析PDF(file_name, llm_kwargs, plugin_kwargs, chatbot, history, system_pro
)
iteration_results.append(gpt_say)
last_iteration_result = gpt_say
############################## <第 3 步整理history> ##################################
final_results.extend(iteration_results)
# 将摘要添加到历史中,方便"猜你想问"使用
history.extend([last_iteration_result])
final_results.append(f'接下来,你是一名专业的学术教授,利用以上信息,使用中文回答我的问题。')
# 接下来两句话只显示在界面上,不起实际作用
i_say_show_user = f'接下来,你是一名专业的学术教授,利用以上信息,使用中文回答我的问题。'; gpt_say = "[Local Message] 收到。"
@ -112,3 +113,4 @@ def 理解PDF文档内容标准文件输入(txt, llm_kwargs, plugin_kwargs, chat
txt = file_manifest[0]
# 开始正式执行任务
yield from 解析PDF(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt)

View File

@ -144,3 +144,13 @@ def 解析ipynb文件(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_p
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
return
yield from ipynb解释(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, )
if __name__ == '__main__':
import json
filename = ''
code = parseNotebook(filename)
print(code)
with open(filename, 'r', encoding='utf-8', errors='replace') as f:
notebook = f.read()
print(notebook)

View File

@ -13,8 +13,13 @@ def 猜你想问(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt
show_say = txt
prompt = txt+'\n回答完问题后,再列出用户可能提出的三个问题。'
else:
prompt = history[-1]+"\n分析上述回答,再列出用户可能提出的三个问题。"
show_say = '分析上述回答,再列出用户可能提出的三个问题。'
try:
prompt = history[-1]+f"\n{show_say}"
except IndexError:
prompt = system_prompt+"\n再列出用户可能提出的三个问题。"
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
inputs=prompt,
inputs_show_user=show_say,
@ -23,6 +28,8 @@ def 猜你想问(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt
history=history,
sys_prompt=system_prompt
)
chatbot[-1] = (show_say, gpt_say)
history.extend([show_say, gpt_say])
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面

BIN
docs/assets/PLAI.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

806
docs/assets/custom.css Normal file
View File

@ -0,0 +1,806 @@
:root {
--chatbot-color-light: #000000;
--chatbot-color-dark: #FFFFFF;
--chatbot-background-color-light: #F3F3F3;
--chatbot-background-color-dark: #121111;
--message-user-background-color-light: #95EC69;
--message-user-background-color-dark: #26B561;
--message-bot-background-color-light: #FFFFFF;
--message-bot-background-color-dark: #2C2C2C;
}
mspace {
display: block;
}
@media only screen and (max-width: 767px) {
#column_1 {
display: none !important;
}
}
@keyframes highlight {
0%, 100% {
border: 2px solid transparent;
}
50% {
border-color: yellow;
}
}
#highlight_update {
animation-name: highlight;
animation-duration: 0.75s;
animation-iteration-count: 3;
}
.table-wrap.svelte-13hsdno.svelte-13hsdno.svelte-13hsdno {
border: 0px solid var(--border-color-primary) !important;
}
#examples_col {
z-index: 2;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
margin-bottom: 30% !important;
}
#hide_examples {
z-index: 0;
}
#debug_mes {
position: absolute;
display: flex;
bottom: 0;
left: 0;
z-index: 1; /* 设置更高的 z-index 值 */
margin-bottom: -4px !important;
align-self: flex-end;
}
#chat_box {
display: flex;
flex-direction: column;
overflow-y: visible !important;
z-index: 3;
flex-grow: 1; /* 自动填充剩余空间 */
position: absolute;
bottom: 0;
left: 0;
width: 100%;
margin-bottom: 30px !important;
border: 1px solid var(--border-color-primary);
}
.toast-body {
z-index: 5 !important;
}
.chat_input {
}
.sm_btn {
position: relative;
bottom: 5px;
height: 10%;
border-radius: 20px!important;
min-width: min(10%,100%) !important;
overflow: hidden;
}
.sm_select {
position: relative !important;
z-index: 5 !important;
bottom: 5px;
min-width: min(20%,100%) !important;
border-radius: 20px!important;
}
.sm_checkbox {
position: relative !important;
z-index: 5 !important;
bottom: 5px;
padding: 0 !important;
}
.sm_select .wrap-inner.svelte-aqlk7e.svelte-aqlk7e.svelte-aqlk7e {
padding: 0 !important;
}
.sm_select .block.svelte-mppz8v {
width: 10% !important;
}
/* usage_display */
.insert_block {
position: relative;
bottom: 2px;
min-width: min(55px,100%) !important;
}
.submit_btn {
flex-direction: column-reverse;
overflow-y: auto !important;
position: absolute;
bottom: 0;
right: 10px;
margin-bottom: 10px !important;
min-width: min(50px,100%) !important;
}
textarea {
resize: none;
height: 100%; /* 填充父元素的高度 */
}
#main_chatbot {
height: 75vh !important;
max-height: 75vh !important;
/* overflow: auto !important; */
z-index: 2;
transform: translateZ(0) !important;
backface-visibility: hidden !important;
will-change: transform !important;
}
#prompt_result{
height: 60vh !important;
max-height: 60vh !important;
}
#app_title {
font-weight: var(--prose-header-text-weight);
font-size: var(--text-xxl);
line-height: 1.3;
text-align: left;
margin-top: 6px;
white-space: nowrap;
}
#description {
text-align: center;
margin: 32px 0 4px 0;
}
/* gradio的页脚信息 */
footer {
/* display: none !important; */
margin-top: .2em !important;
font-size: 85%;
}
#footer {
text-align: center;
}
#footer div {
display: inline-block;
}
#footer .versions{
font-size: 85%;
opacity: 0.60;
}
#float_display {
position: absolute;
max-height: 30px;
}
/* user_info */
#user_info {
white-space: nowrap;
position: absolute; left: 8em; top: .2em;
z-index: var(--layer-2);
box-shadow: var(--block-shadow);
border: none; border-radius: var(--block-label-radius);
background: var(--color-accent);
padding: var(--block-label-padding);
font-size: var(--block-label-text-size); line-height: var(--line-sm);
width: auto; min-height: 30px !important;
opacity: 1;
transition: opacity 0.3s ease-in-out;
}
textarea.svelte-1pie7s6 {
background: #e7e6e6 !important;
width: 96% !important;
}
.dark textarea.svelte-1pie7s6 {
background: var(--input-background-fill) !important;
width: 96% !important;
}
.dark input[type=number].svelte-1cl284s {
background: #393939 !important;
border: var(--input-border-width) solid var(--input-border-color) !important;
}
.dark input[type="range"] {
background: #393939 !important;
}
#user_info .wrap {
opacity: 0;
}
#user_info p {
color: white;
font-weight: var(--block-label-text-weight);
}
#user_info.hideK {
opacity: 0;
transition: opacity 1s ease-in-out;
}
[class *= "message"] {
gap: 7px !important;
border-radius: var(--radius-xl) !important
}
/* debug_mes */
#debug_mes {
min-height: 2em;
align-items: flex-end;
justify-content: flex-end;
}
#debug_mes p {
font-size: .85em;
font-family: ui-monospace, "SF Mono", "SFMono-Regular", "Menlo", "Consolas", "Liberation Mono", "Microsoft Yahei UI", "Microsoft Yahei", monospace;
/* Windows下中文的monospace会fallback为新宋体实在太丑这里折中使用微软雅黑 */
color: #000000;
}
.dark #debug_mes p {
color: #ee65ed;
}
#debug_mes {
transition: all 0.6s;
}
#main_chatbot {
transition: height 0.3s ease;
}
.wrap.svelte-18telvq.svelte-18telvq {
padding: var(--block-padding) !important;
height: 100% !important;
max-height: 95% !important;
overflow-y: auto !important;
}
.app.svelte-1mya07g.svelte-1mya07g {
max-width: 100%;
position: relative;
/* margin: auto; */
padding: var(--size-4);
width: 100%;
height: 100%;
}
.gradio-container-3-32-2 h1 {
font-weight: 700 !important;
font-size: 28px !important;
}
.gradio-container-3-32-2 h2 {
font-weight: 600 !important;
font-size: 24px !important;
}
.gradio-container-3-32-2 h3 {
font-weight: 500 !important;
font-size: 20px !important;
}
.gradio-container-3-32-2 h4 {
font-weight: 400 !important;
font-size: 16px !important;
}
.gradio-container-3-32-2 h5 {
font-weight: 300 !important;
font-size: 14px !important;
}
.gradio-container-3-32-2 h6 {
font-weight: 200 !important;
font-size: 12px !important;
}
#usage_display p, #usage_display span {
margin: 0;
font-size: .85em;
color: var(--body-text-color-subdued);
}
.progress-bar {
background-color: var(--input-background-fill);;
margin: .5em 0 !important;
height: 20px;
border-radius: 10px;
overflow: hidden;
}
.progress {
background-color: var(--block-title-background-fill);
height: 100%;
border-radius: 10px;
text-align: right;
transition: width 0.5s ease-in-out;
}
.progress-text {
/* color: white; */
color: var(--color-accent) !important;
font-size: 1em !important;
font-weight: bold;
padding-right: 10px;
line-height: 20px;
}
.apSwitch {
top: 2px;
display: inline-block;
height: 24px;
position: relative;
width: 48px;
border-radius: 12px;
}
.apSwitch input {
display: none !important;
}
.apSlider {
background-color: var(--neutral-200);
bottom: 0;
cursor: pointer;
left: 0;
position: absolute;
right: 0;
top: 0;
transition: .4s;
font-size: 18px;
border-radius: 7px;
}
.apSlider::before {
bottom: -1.5px;
left: 1px;
position: absolute;
transition: .4s;
content: "🌞";
}
hr.append-display {
margin: 8px 0;
border: none;
height: 1px;
border-top-width: 0;
background-image: linear-gradient(to right, rgba(50,50,50, 0.1), rgba(150, 150, 150, 0.8), rgba(50,50,50, 0.1));
}
.source-a {
font-size: 0.8em;
max-width: 100%;
margin: 0;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
/* background-color: #dddddd88; */
border-radius: 1.5rem;
padding: 0.2em;
}
.source-a a {
display: inline-block;
background-color: #aaaaaa50;
border-radius: 1rem;
padding: 0.5em;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
min-width: 20%;
white-space: nowrap;
margin: 0.2rem 0.1rem;
text-decoration: none !important;
flex: 1;
transition: flex 0.5s;
}
.source-a a:hover {
background-color: #aaaaaa20;
flex: 2;
}
input:checked + .apSlider {
background-color: var(--primary-600);
}
input:checked + .apSlider::before {
transform: translateX(23px);
content:"🌚";
}
/* Override Slider Styles (for webkit browsers like Safari and Chrome)
* 好希望这份提案能早日实现 https://github.com/w3c/csswg-drafts/issues/4410
* 进度滑块在各个平台还是太不统一了
*/
input[type="range"] {
-webkit-appearance: none;
height: 4px;
background: var(--input-background-fill);
border-radius: 5px;
background-image: linear-gradient(var(--primary-500),var(--primary-500));
background-size: 0% 100%;
background-repeat: no-repeat;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 20px;
width: 20px;
border-radius: 50%;
border: solid 0.5px #ddd;
background-color: white;
cursor: ew-resize;
box-shadow: var(--input-shadow);
transition: background-color .1s ease;
}
input[type="range"]::-webkit-slider-thumb:hover {
background: var(--neutral-50);
}
input[type=range]::-webkit-slider-runnable-track {
-webkit-appearance: none;
box-shadow: none;
border: none;
background: transparent;
}
.submit_btn, #cancel_btn {
height: 42px !important;
}
.submit_btn::before {
content: url("data:image/svg+xml, %3Csvg width='21px' height='20px' viewBox='0 0 21 20' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E %3Cg id='page' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E %3Cg id='send' transform='translate(0.435849, 0.088463)' fill='%23FFFFFF' fill-rule='nonzero'%3E %3Cpath d='M0.579148261,0.0428666046 C0.301105539,-0.0961547561 -0.036517765,0.122307382 0.0032026237,0.420210298 L1.4927172,18.1553639 C1.5125774,18.4334066 1.79062012,18.5922882 2.04880264,18.4929872 L8.24518329,15.8913017 L11.6412765,19.7441794 C11.8597387,19.9825018 12.2370824,19.8832008 12.3165231,19.5852979 L13.9450591,13.4882182 L19.7839562,11.0255541 C20.0619989,10.8865327 20.0818591,10.4694687 19.7839562,10.3105871 L0.579148261,0.0428666046 Z M11.6138902,17.0883151 L9.85385903,14.7195502 L0.718169621,0.618812241 L12.69945,12.9346347 L11.6138902,17.0883151 Z' id='shape'%3E%3C/path%3E %3C/g%3E %3C/g%3E %3C/svg%3E");
height: 21px;
}
#cancel_btn::before {
content: url("data:image/svg+xml,%3Csvg width='21px' height='21px' viewBox='0 0 21 21' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E %3Cg id='pg' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E %3Cpath d='M10.2072007,20.088463 C11.5727865,20.088463 12.8594566,19.8259823 14.067211,19.3010209 C15.2749653,18.7760595 16.3386126,18.0538087 17.2581528,17.1342685 C18.177693,16.2147282 18.8982283,15.1527965 19.4197586,13.9484733 C19.9412889,12.7441501 20.202054,11.4557644 20.202054,10.0833163 C20.202054,8.71773046 19.9395733,7.43106036 19.4146119,6.22330603 C18.8896505,5.01555169 18.1673997,3.95018885 17.2478595,3.0272175 C16.3283192,2.10424615 15.2646719,1.3837109 14.0569176,0.865611739 C12.8491633,0.34751258 11.5624932,0.088463 10.1969073,0.088463 C8.83132146,0.088463 7.54636692,0.34751258 6.34204371,0.865611739 C5.1377205,1.3837109 4.07407321,2.10424615 3.15110186,3.0272175 C2.22813051,3.95018885 1.5058797,5.01555169 0.984349419,6.22330603 C0.46281914,7.43106036 0.202054,8.71773046 0.202054,10.0833163 C0.202054,11.4557644 0.4645347,12.7441501 0.9894961,13.9484733 C1.5144575,15.1527965 2.23670831,16.2147282 3.15624854,17.1342685 C4.07578877,18.0538087 5.1377205,18.7760595 6.34204371,19.3010209 C7.54636692,19.8259823 8.83475258,20.088463 10.2072007,20.088463 Z M10.2072007,18.2562448 C9.07493099,18.2562448 8.01471483,18.0452309 7.0265522,17.6232031 C6.03838956,17.2011753 5.17031614,16.6161693 4.42233192,15.8681851 C3.6743477,15.1202009 3.09105726,14.2521274 2.67246059,13.2639648 C2.25386392,12.2758022 2.04456558,11.215586 2.04456558,10.0833163 C2.04456558,8.95104663 2.25386392,7.89083047 2.67246059,6.90266784 C3.09105726,5.9145052 3.6743477,5.04643178 4.42233192,4.29844756 C5.17031614,3.55046334 6.036674,2.9671729 7.02140552,2.54857623 C8.00613703,2.12997956 9.06463763,1.92068122 10.1969073,1.92068122 C11.329177,1.92068122 12.3911087,2.12997956 13.3827025,2.54857623 C14.3742962,2.9671729 15.2440852,3.55046334 15.9920694,4.29844756 C16.7400537,5.04643178 17.3233441,5.9145052 17.7419408,6.90266784 C18.1605374,7.89083047 18.3698358,8.95104663 18.3698358,10.0833163 C18.3698358,11.215586 18.1605374,12.2758022 17.7419408,13.2639648 C17.3233441,14.2521274 16.7400537,15.1202009 15.9920694,15.8681851 C15.2440852,16.6161693 14.3760118,17.2011753 13.3878492,17.6232031 C12.3996865,18.0452309 11.3394704,18.2562448 10.2072007,18.2562448 Z M7.65444721,13.6242324 L12.7496608,13.6242324 C13.0584616,13.6242324 13.3003556,13.5384544 13.4753427,13.3668984 C13.6503299,13.1953424 13.7378234,12.9585951 13.7378234,12.6566565 L13.7378234,7.49968276 C13.7378234,7.19774418 13.6503299,6.96099688 13.4753427,6.78944087 C13.3003556,6.61788486 13.0584616,6.53210685 12.7496608,6.53210685 L7.65444721,6.53210685 C7.33878414,6.53210685 7.09345904,6.61788486 6.91847191,6.78944087 C6.74348478,6.96099688 6.65599121,7.19774418 6.65599121,7.49968276 L6.65599121,12.6566565 C6.65599121,12.9585951 6.74348478,13.1953424 6.91847191,13.3668984 C7.09345904,13.5384544 7.33878414,13.6242324 7.65444721,13.6242324 Z' id='shape' fill='%23FF3B30' fill-rule='nonzero'%3E%3C/path%3E %3C/g%3E %3C/svg%3E");
height: 21px;
}
/* list */
ol:not(.options), ul:not(.options) {
padding-inline-start: 2em !important;
}
/* 亮色(默认) */
#main_chatbot {
background-color: var(--chatbot-background-color-light) !important;
color: var(--chatbot-color-light) !important;
}
/* 暗色 */
.dark #main_chatbot {
background-color: var(--block-background-fill) !important;
color: var(--chatbot-color-dark) !important;
}
/* 屏幕宽度大于等于500px的设备 */
/* update on 2023.4.8: 高度的细致调整已写入JavaScript */
@media screen and (min-width: 500px) {
#main_chatbot {
height: calc(100vh - 200px);
}
#main_chatbot .wrap {
max-height: calc(100vh - 200px - var(--line-sm)*1rem - 2*var(--block-label-margin) );
}
}
/* 屏幕宽度小于500px的设备 */
@media screen and (max-width: 499px) {
#main_chatbot {
height: calc(100vh - 140px);
}
#main_chatbot .wrap {
max-height: calc(100vh - 140px - var(--line-sm)*1rem - 2*var(--block-label-margin) );
}
[data-testid = "bot"] {
max-width: 95% !important;
}
#app_title h1{
letter-spacing: -1px; font-size: 22px;
}
}
#main_chatbot .wrap {
overflow-x: hidden
}
/* 对话气泡 */
.message {
border-radius: var(--radius-xl) !important;
border: none;
padding: var(--spacing-xl) !important;
font-size: 15px !important;
line-height: var(--line-md) !important;
min-height: calc(var(--text-md)*var(--line-md) + 2*var(--spacing-xl));
min-width: calc(var(--text-md)*var(--line-md) + 2*var(--spacing-xl));
}
[data-testid = "bot"] {
max-width: 85%;
border-bottom-left-radius: 0 !important;
}
[data-testid = "user"] {
max-width: 85%;
width: auto !important;
border-bottom-right-radius: 0 !important;
}
.message p {
margin-top: 0.6em !important;
margin-bottom: 0.6em !important;
}
.message p:first-child { margin-top: 0 !important; }
.message p:last-of-type { margin-bottom: 0 !important; }
.message .md-message {
display: block;
padding: 0 !important;
}
.message .raw-message {
display: block;
padding: 0 !important;
white-space: pre-wrap;
}
.raw-message.hideM, .md-message.hideM {
display: none;
}
/* custom buttons */
.chuanhu-btn {
border-radius: 5px;
/* background-color: #E6E6E6 !important; */
color: rgba(120, 120, 120, 0.64) !important;
padding: 4px !important;
position: absolute;
right: -22px;
cursor: pointer !important;
transition: color .2s ease, background-color .2s ease;
}
.chuanhu-btn:hover {
background-color: rgba(167, 167, 167, 0.25) !important;
color: unset !important;
}
.chuanhu-btn:active {
background-color: rgba(167, 167, 167, 0.5) !important;
}
.chuanhu-btn:focus {
outline: none;
}
.copy-bot-btn {
/* top: 18px; */
bottom: 0;
}
.toggle-md-btn {
/* top: 0; */
bottom: 20px;
}
.copy-code-btn {
position: relative;
float: right;
font-size: 1em;
cursor: pointer;
}
.message-wrap>div img{
border-radius: 10px !important;
}
/* history message */
.wrap>.history-message {
padding: 10px !important;
}
.history-message {
/* padding: 0 !important; */
opacity: 80%;
display: flex;
flex-direction: column;
}
.history-message>.history-message {
padding: 0 !important;
}
.history-message>.message-wrap {
padding: 0 !important;
margin-bottom: 16px;
}
.history-message>.message {
margin-bottom: 16px;
}
.wrap>.history-message::after {
content: "";
display: block;
height: 2px;
background-color: var(--body-text-color-subdued);
margin-bottom: 10px;
margin-top: -10px;
clear: both;
}
.wrap>.history-message>:last-child::after {
content: "仅供查看";
display: block;
text-align: center;
color: var(--body-text-color-subdued);
font-size: 0.8em;
}
/* 表格 */
table {
margin: 1em 0;
border-collapse: collapse;
empty-cells: show;
}
td,th {
border: 1.2px solid var(--border-color-primary) !important;
padding: 0.2em;
}
thead {
background-color: rgba(175,184,193,0.2);
}
thead th {
padding: .5em .2em;
}
/* 行内代码 */
.message :not(pre) code {
display: inline;
white-space: break-spaces;
border-radius: 6px;
margin: 0 2px 0 2px;
padding: .2em .4em .1em .4em;
background-color: rgba(175,184,193,0.2);
}
/* 代码块 */
.message pre code {
display: block;
overflow: auto;
white-space: pre;
background-color: hsla(0, 0%, 7%, 70%)!important;
border-radius: 10px;
padding: 1.2em 1em 0em .5em;
margin: 0.6em 2em 1em 0.2em;
color: #FFF;
box-shadow: 6px 6px 16px hsla(0, 0%, 0%, 0.2);
}
.dark .message pre code {
background-color: hsla(0, 0%, 20%, 300%)!important;
}
.message pre {
padding: 0 !important;
}
.message pre code div.highlight {
background-color: unset !important;
}
button.copy-button {
display: none;
}
/* 代码高亮样式 */
.codehilite .hll { background-color: #6e7681 }
.codehilite .c { color: #8b949e; font-style: italic } /* Comment */
.codehilite .err { color: #f85149 } /* Error */
.codehilite .esc { color: #c9d1d9 } /* Escape */
.codehilite .g { color: #c9d1d9 } /* Generic */
.codehilite .k { color: #ff7b72 } /* Keyword */
.codehilite .l { color: #a5d6ff } /* Literal */
.codehilite .n { color: #c9d1d9 } /* Name */
.codehilite .o { color: #ff7b72; font-weight: bold } /* Operator */
.codehilite .x { color: #c9d1d9 } /* Other */
.codehilite .p { color: #c9d1d9 } /* Punctuation */
.codehilite .ch { color: #8b949e; font-style: italic } /* Comment.Hashbang */
.codehilite .cm { color: #8b949e; font-style: italic } /* Comment.Multiline */
.codehilite .cp { color: #8b949e; font-weight: bold; font-style: italic } /* Comment.Preproc */
.codehilite .cpf { color: #8b949e; font-style: italic } /* Comment.PreprocFile */
.codehilite .c1 { color: #8b949e; font-style: italic } /* Comment.Single */
.codehilite .cs { color: #8b949e; font-weight: bold; font-style: italic } /* Comment.Special */
.codehilite .gd { color: #ffa198; background-color: #490202 } /* Generic.Deleted */
.codehilite .ge { color: #c9d1d9; font-style: italic } /* Generic.Emph */
.codehilite .gr { color: #ffa198 } /* Generic.Error */
.codehilite .gh { color: #79c0ff; font-weight: bold } /* Generic.Heading */
.codehilite .gi { color: #56d364; background-color: #0f5323 } /* Generic.Inserted */
.codehilite .go { color: #8b949e } /* Generic.Output */
.codehilite .gp { color: #8b949e } /* Generic.Prompt */
.codehilite .gs { color: #c9d1d9; font-weight: bold } /* Generic.Strong */
.codehilite .gu { color: #79c0ff } /* Generic.Subheading */
.codehilite .gt { color: #ff7b72 } /* Generic.Traceback */
.codehilite .g-Underline { color: #c9d1d9; text-decoration: underline } /* Generic.Underline */
.codehilite .kc { color: #79c0ff } /* Keyword.Constant */
.codehilite .kd { color: #ff7b72 } /* Keyword.Declaration */
.codehilite .kn { color: #ff7b72 } /* Keyword.Namespace */
.codehilite .kp { color: #79c0ff } /* Keyword.Pseudo */
.codehilite .kr { color: #ff7b72 } /* Keyword.Reserved */
.codehilite .kt { color: #ff7b72 } /* Keyword.Type */
.codehilite .ld { color: #79c0ff } /* Literal.Date */
.codehilite .m { color: #a5d6ff } /* Literal.Number */
.codehilite .s { color: #a5d6ff } /* Literal.String */
.codehilite .na { color: #c9d1d9 } /* Name.Attribute */
.codehilite .nb { color: #c9d1d9 } /* Name.Builtin */
.codehilite .nc { color: #f0883e; font-weight: bold } /* Name.Class */
.codehilite .no { color: #79c0ff; font-weight: bold } /* Name.Constant */
.codehilite .nd { color: #d2a8ff; font-weight: bold } /* Name.Decorator */
.codehilite .ni { color: #ffa657 } /* Name.Entity */
.codehilite .ne { color: #f0883e; font-weight: bold } /* Name.Exception */
.codehilite .nf { color: #d2a8ff; font-weight: bold } /* Name.Function */
.codehilite .nl { color: #79c0ff; font-weight: bold } /* Name.Label */
.codehilite .nn { color: #ff7b72 } /* Name.Namespace */
.codehilite .nx { color: #c9d1d9 } /* Name.Other */
.codehilite .py { color: #79c0ff } /* Name.Property */
.codehilite .nt { color: #7ee787 } /* Name.Tag */
.codehilite .nv { color: #79c0ff } /* Name.Variable */
.codehilite .ow { color: #ff7b72; font-weight: bold } /* Operator.Word */
.codehilite .pm { color: #c9d1d9 } /* Punctuation.Marker */
.codehilite .w { color: #6e7681 } /* Text.Whitespace */
.codehilite .mb { color: #a5d6ff } /* Literal.Number.Bin */
.codehilite .mf { color: #a5d6ff } /* Literal.Number.Float */
.codehilite .mh { color: #a5d6ff } /* Literal.Number.Hex */
.codehilite .mi { color: #a5d6ff } /* Literal.Number.Integer */
.codehilite .mo { color: #a5d6ff } /* Literal.Number.Oct */
.codehilite .sa { color: #79c0ff } /* Literal.String.Affix */
.codehilite .sb { color: #a5d6ff } /* Literal.String.Backtick */
.codehilite .sc { color: #a5d6ff } /* Literal.String.Char */
.codehilite .dl { color: #79c0ff } /* Literal.String.Delimiter */
.codehilite .sd { color: #a5d6ff } /* Literal.String.Doc */
.codehilite .s2 { color: #a5d6ff } /* Literal.String.Double */
.codehilite .se { color: #79c0ff } /* Literal.String.Escape */
.codehilite .sh { color: #79c0ff } /* Literal.String.Heredoc */
.codehilite .si { color: #a5d6ff } /* Literal.String.Interpol */
.codehilite .sx { color: #a5d6ff } /* Literal.String.Other */
.codehilite .sr { color: #79c0ff } /* Literal.String.Regex */
.codehilite .s1 { color: #a5d6ff } /* Literal.String.Single */
.codehilite .ss { color: #a5d6ff } /* Literal.String.Symbol */
.codehilite .bp { color: #c9d1d9 } /* Name.Builtin.Pseudo */
.codehilite .fm { color: #d2a8ff; font-weight: bold } /* Name.Function.Magic */
.codehilite .vc { color: #79c0ff } /* Name.Variable.Class */
.codehilite .vg { color: #79c0ff } /* Name.Variable.Global */
.codehilite .vi { color: #79c0ff } /* Name.Variable.Instance */
.codehilite .vm { color: #79c0ff } /* Name.Variable.Magic */
.codehilite .il { color: #a5d6ff } /* Literal.Number.Integer.Long */
.dark .codehilite .hll { background-color: #2C3B41 }
.dark .codehilite .c { color: #79d618; font-style: italic } /* Comment */
.dark .codehilite .err { color: #FF5370 } /* Error */
.dark .codehilite .esc { color: #89DDFF } /* Escape */
.dark .codehilite .g { color: #EEFFFF } /* Generic */
.dark .codehilite .k { color: #BB80B3 } /* Keyword */
.dark .codehilite .l { color: #C3E88D } /* Literal */
.dark .codehilite .n { color: #EEFFFF } /* Name */
.dark .codehilite .o { color: #89DDFF } /* Operator */
.dark .codehilite .p { color: #89DDFF } /* Punctuation */
.dark .codehilite .ch { color: #79d618; font-style: italic } /* Comment.Hashbang */
.dark .codehilite .cm { color: #79d618; font-style: italic } /* Comment.Multiline */
.dark .codehilite .cp { color: #79d618; font-style: italic } /* Comment.Preproc */
.dark .codehilite .cpf { color: #79d618; font-style: italic } /* Comment.PreprocFile */
.dark .codehilite .c1 { color: #79d618; font-style: italic } /* Comment.Single */
.dark .codehilite .cs { color: #79d618; font-style: italic } /* Comment.Special */
.dark .codehilite .gd { color: #FF5370 } /* Generic.Deleted */
.dark .codehilite .ge { color: #89DDFF } /* Generic.Emph */
.dark .codehilite .gr { color: #FF5370 } /* Generic.Error */
.dark .codehilite .gh { color: #C3E88D } /* Generic.Heading */
.dark .codehilite .gi { color: #C3E88D } /* Generic.Inserted */
.dark .codehilite .go { color: #79d618 } /* Generic.Output */
.dark .codehilite .gp { color: #FFCB6B } /* Generic.Prompt */
.dark .codehilite .gs { color: #FF5370 } /* Generic.Strong */
.dark .codehilite .gu { color: #89DDFF } /* Generic.Subheading */
.dark .codehilite .gt { color: #FF5370 } /* Generic.Traceback */
.dark .codehilite .kc { color: #89DDFF } /* Keyword.Constant */
.dark .codehilite .kd { color: #BB80B3 } /* Keyword.Declaration */
.dark .codehilite .kn { color: #89DDFF; font-style: italic } /* Keyword.Namespace */
.dark .codehilite .kp { color: #89DDFF } /* Keyword.Pseudo */
.dark .codehilite .kr { color: #BB80B3 } /* Keyword.Reserved */
.dark .codehilite .kt { color: #BB80B3 } /* Keyword.Type */
.dark .codehilite .ld { color: #C3E88D } /* Literal.Date */
.dark .codehilite .m { color: #F78C6C } /* Literal.Number */
.dark .codehilite .s { color: #C3E88D } /* Literal.String */
.dark .codehilite .na { color: #BB80B3 } /* Name.Attribute */
.dark .codehilite .nb { color: #82AAFF } /* Name.Builtin */
.dark .codehilite .nc { color: #FFCB6B } /* Name.Class */
.dark .codehilite .no { color: #EEFFFF } /* Name.Constant */
.dark .codehilite .nd { color: #82AAFF } /* Name.Decorator */
.dark .codehilite .ni { color: #89DDFF } /* Name.Entity */
.dark .codehilite .ne { color: #FFCB6B } /* Name.Exception */
.dark .codehilite .nf { color: #82AAFF } /* Name.Function */
.dark .codehilite .nl { color: #82AAFF } /* Name.Label */
.dark .codehilite .nn { color: #FFCB6B } /* Name.Namespace */
.dark .codehilite .nx { color: #EEFFFF } /* Name.Other */
.dark .codehilite .py { color: #FFCB6B } /* Name.Property */
.dark .codehilite .nt { color: #FF5370 } /* Name.Tag */
.dark .codehilite .nv { color: #89DDFF } /* Name.Variable */
.dark .codehilite .ow { color: #89DDFF; font-style: italic } /* Operator.Word */
.dark .codehilite .pm { color: #89DDFF } /* Punctuation.Marker */
.dark .codehilite .w { color: #EEFFFF } /* Text.Whitespace */
.dark .codehilite .mb { color: #F78C6C } /* Literal.Number.Bin */
.dark .codehilite .mf { color: #F78C6C } /* Literal.Number.Float */
.dark .codehilite .mh { color: #F78C6C } /* Literal.Number.Hex */
.dark .codehilite .mi { color: #F78C6C } /* Literal.Number.Integer */
.dark .codehilite .mo { color: #F78C6C } /* Literal.Number.Oct */
.dark .codehilite .sa { color: #BB80B3 } /* Literal.String.Affix */
.dark .codehilite .sb { color: #C3E88D } /* Literal.String.Backtick */
.dark .codehilite .sc { color: #C3E88D } /* Literal.String.Char */
.dark .codehilite .dl { color: #EEFFFF } /* Literal.String.Delimiter */
.dark .codehilite .sd { color: #79d618; font-style: italic } /* Literal.String.Doc */
.dark .codehilite .s2 { color: #C3E88D } /* Literal.String.Double */
.dark .codehilite .se { color: #EEFFFF } /* Literal.String.Escape */
.dark .codehilite .sh { color: #C3E88D } /* Literal.String.Heredoc */
.dark .codehilite .si { color: #89DDFF } /* Literal.String.Interpol */
.dark .codehilite .sx { color: #C3E88D } /* Literal.String.Other */
.dark .codehilite .sr { color: #89DDFF } /* Literal.String.Regex */
.dark .codehilite .s1 { color: #C3E88D } /* Literal.String.Single */
.dark .codehilite .ss { color: #89DDFF } /* Literal.String.Symbol */
.dark .codehilite .bp { color: #89DDFF } /* Name.Builtin.Pseudo */
.dark .codehilite .fm { color: #82AAFF } /* Name.Function.Magic */
.dark .codehilite .vc { color: #89DDFF } /* Name.Variable.Class */
.dark .codehilite .vg { color: #89DDFF } /* Name.Variable.Global */
.dark .codehilite .vi { color: #89DDFF } /* Name.Variable.Instance */
.dark .codehilite .vm { color: #82AAFF } /* Name.Variable.Magic */
.dark .codehilite .il { color: #F78C6C } /* Literal.Number.Integer.Long */

465
docs/assets/custom.js Normal file
View File

@ -0,0 +1,465 @@
// custom javascript here
const MAX_HISTORY_LENGTH = 32;
var key_down_history = [];
var currentIndex = -1;
var user_input_ta;
var gradioContainer = null;
var user_input_ta = null;
var chat_txt = null;
var userInfoDiv = null;
var appTitleDiv = null;
var chatbot = null;
var chatbotWrap = null;
var apSwitch = null;
var messageBotDivs = null;
var loginUserForm = null;
var logginUser = null;
var userLogged = false;
var usernameGotten = false;
var historyLoaded = false;
var ga = document.getElementsByTagName("gradio-app");
var targetNode = ga[0];
var isInIframe = (window.self !== window.top);
var language = navigator.language.slice(0,2);
var forView_i18n = {
'zh': "仅供查看",
'en': "For viewing only",
'ja': "閲覧専用",
'fr': "Pour consultation seulement",
'es': "Solo para visualización",
};
var deleteConfirm_i18n_pref = {
'zh': "你真的要删除 ",
'en': "Are you sure you want to delete ",
'ja': "本当に ",
};
var deleteConfirm_i18n_suff = {
'zh': " 吗?",
'en': " ?",
'ja': " を削除してもよろしいですか?",
};
var deleteConfirm_msg_pref = "Are you sure you want to delete ";
var deleteConfirm_msg_suff = " ?";
// gradio 页面加载好了么??? 我能动你的元素了么??
function gradioLoaded(mutations) {
for (var i = 0; i < mutations.length; i++) {
if (mutations[i].addedNodes.length) {
loginUserForm = document.querySelector(".gradio-container > .main > .wrap > .panel > .form")
gradioContainer = document.querySelector(".gradio-container");
chat_txt = document.getElementById('chat_txt');
userInfoDiv = document.getElementById("user_info");
appTitleDiv = document.getElementById("app_title");
chatbot = document.querySelector('#废弃');
chatbotWrap = document.querySelector('#废弃 > .wrap');
apSwitch = document.querySelector('.apSwitch input[type="checkbox"]');
if (loginUserForm) {
localStorage.setItem("userLogged", true);
userLogged = true;
}
if (gradioContainer && apSwitch) { // gradioCainter 加载出来了没?
adjustDarkMode();
}
if (chat_txt) { // chat_txt 加载出来了没?
selectHistory();
}
if (userInfoDiv && appTitleDiv) { // userInfoDiv 和 appTitleDiv 加载出来了没?
if (!usernameGotten) {
getUserInfo();
}
setTimeout(showOrHideUserInfo(), 2000);
}
if (chatbot) { // chatbot 加载出来了没?
setChatbotHeight();
}
if (chatbotWrap) {
if (!historyLoaded) {
loadHistoryHtml();
}
setChatbotScroll();
}
}
}
}
function webLocale() {
// console.log("webLocale", language);
if (forView_i18n.hasOwnProperty(language)) {
var forView = forView_i18n[language];
var forViewStyle = document.createElement('style');
forViewStyle.innerHTML = '.wrap>.history-message>:last-child::after { content: "' + forView + '"!important; }';
document.head.appendChild(forViewStyle);
}
if (deleteConfirm_i18n_pref.hasOwnProperty(language)) {
deleteConfirm_msg_pref = deleteConfirm_i18n_pref[language];
deleteConfirm_msg_suff = deleteConfirm_i18n_suff[language];
}
}
function showConfirmationDialog(a, file, c) {
if (file != "") {
var result = confirm(deleteConfirm_msg_pref + file + deleteConfirm_msg_suff);
if (result) {
return [a, file, c];
}
}
return [a, "CANCELED", c];
}
function selectHistory() {
user_input_ta = chat_txt.querySelector("textarea");
if (user_input_ta) {
observer.disconnect(); // 停止监听
// 在 textarea 上监听 keydown 事件
user_input_ta.addEventListener("keydown", function (event) {
var value = user_input_ta.value.trim();
// 判断按下的是否为方向键
if (event.code === 'ArrowUp' || event.code === 'ArrowDown') {
// 如果按下的是方向键,且输入框中有内容,且历史记录中没有该内容,则不执行操作
if (value && key_down_history.indexOf(value) === -1)
return;
// 对于需要响应的动作,阻止默认行为。
event.preventDefault();
var length = key_down_history.length;
if (length === 0) {
currentIndex = -1; // 如果历史记录为空,直接将当前选中的记录重置
return;
}
if (currentIndex === -1) {
currentIndex = length;
}
if (event.code === 'ArrowUp' && currentIndex > 0) {
currentIndex--;
user_input_ta.value = key_down_history[currentIndex];
} else if (event.code === 'ArrowDown' && currentIndex < length - 1) {
currentIndex++;
user_input_ta.value = key_down_history[currentIndex];
}
user_input_ta.selectionStart = user_input_ta.value.length;
user_input_ta.selectionEnd = user_input_ta.value.length;
const input_event = new InputEvent("input", { bubbles: true, cancelable: true });
user_input_ta.dispatchEvent(input_event);
} else if (event.code === "Enter") {
if (value) {
currentIndex = -1;
if (key_down_history.indexOf(value) === -1) {
key_down_history.push(value);
if (key_down_history.length > MAX_HISTORY_LENGTH) {
key_down_history.shift();
}
}
}
}
});
}
}
var username = null;
function getUserInfo() {
if (usernameGotten) {
return;
}
userLogged = localStorage.getItem('userLogged');
if (userLogged) {
username = userInfoDiv.innerText;
if (username) {
if (username.includes("getting user info…")) {
setTimeout(getUserInfo, 500);
return;
} else if (username === " ") {
localStorage.removeItem("username");
localStorage.removeItem("userLogged")
userLogged = false;
usernameGotten = true;
return;
} else {
username = username.match(/User:\s*(.*)/)[1] || username;
localStorage.setItem("username", username);
usernameGotten = true;
clearHistoryHtml();
}
}
}
}
function toggleUserInfoVisibility(shouldHide) {
if (userInfoDiv) {
if (shouldHide) {
userInfoDiv.classList.add("hideK");
} else {
userInfoDiv.classList.remove("hideK");
}
}
}
function showOrHideUserInfo() {
var sendBtn = document.getElementById("submit_btn");
// Bind mouse/touch events to show/hide user info
appTitleDiv.addEventListener("mouseenter", function () {
toggleUserInfoVisibility(false);
});
userInfoDiv.addEventListener("mouseenter", function () {
toggleUserInfoVisibility(false);
});
sendBtn.addEventListener("mouseenter", function () {
toggleUserInfoVisibility(false);
});
appTitleDiv.addEventListener("mouseleave", function () {
toggleUserInfoVisibility(true);
});
userInfoDiv.addEventListener("mouseleave", function () {
toggleUserInfoVisibility(true);
});
sendBtn.addEventListener("mouseleave", function () {
toggleUserInfoVisibility(true);
});
appTitleDiv.ontouchstart = function () {
toggleUserInfoVisibility(false);
};
userInfoDiv.ontouchstart = function () {
toggleUserInfoVisibility(false);
};
sendBtn.ontouchstart = function () {
toggleUserInfoVisibility(false);
};
appTitleDiv.ontouchend = function () {
setTimeout(function () {
toggleUserInfoVisibility(true);
}, 3000);
};
userInfoDiv.ontouchend = function () {
setTimeout(function () {
toggleUserInfoVisibility(true);
}, 3000);
};
sendBtn.ontouchend = function () {
setTimeout(function () {
toggleUserInfoVisibility(true);
}, 3000); // Delay 1 second to hide user info
};
// Hide user info after 2 second
setTimeout(function () {
toggleUserInfoVisibility(true);
}, 2000);
}
function toggleDarkMode(isEnabled) {
if (isEnabled) {
document.body.classList.add("dark");
document.body.style.setProperty("background-color", "var(--neutral-950)", "important");
} else {
document.body.classList.remove("dark");
document.body.style.backgroundColor = "";
}
}
function adjustDarkMode() {
const darkModeQuery = window.matchMedia("(prefers-color-scheme: dark)");
// 根据当前颜色模式设置初始状态
apSwitch.checked = darkModeQuery.matches;
toggleDarkMode(darkModeQuery.matches);
// 监听颜色模式变化
darkModeQuery.addEventListener("change", (e) => {
apSwitch.checked = e.matches;
toggleDarkMode(e.matches);
});
// apSwitch = document.querySelector('.apSwitch input[type="checkbox"]');
apSwitch.addEventListener("change", (e) => {
toggleDarkMode(e.target.checked);
});
}
function setChatbotHeight() {
const screenWidth = window.innerWidth;
const statusDisplay = document.querySelector('#status_display');
const statusDisplayHeight = statusDisplay ? statusDisplay.offsetHeight : 0;
const wrap = chatbot.querySelector('.wrap');
const vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
if (isInIframe) {
chatbot.style.height = `700px`;
wrap.style.maxHeight = `calc(700px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`
} else {
if (screenWidth <= 320) {
chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 150}px)`;
wrap.style.maxHeight = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 150}px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`;
} else if (screenWidth <= 499) {
chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 100}px)`;
wrap.style.maxHeight = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 100}px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`;
} else {
chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 160}px)`;
wrap.style.maxHeight = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 160}px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`;
}
}
}
function setChatbotScroll() {
var scrollHeight = chatbotWrap.scrollHeight;
chatbotWrap.scrollTo(0,scrollHeight)
}
var rangeInputs = null;
var numberInputs = null;
function setSlider() {
rangeInputs = document.querySelectorAll('input[type="range"]');
numberInputs = document.querySelectorAll('input[type="number"]')
setSliderRange();
rangeInputs.forEach(rangeInput => {
rangeInput.addEventListener('input', setSliderRange);
});
numberInputs.forEach(numberInput => {
numberInput.addEventListener('input', setSliderRange);
})
}
function setSliderRange() {
var range = document.querySelectorAll('input[type="range"]');
range.forEach(range => {
range.style.backgroundSize = (range.value - range.min) / (range.max - range.min) * 100 + '% 100%';
});
}
function addChuanhuButton(botElement) {
var rawMessage = null;
var mdMessage = null;
rawMessage = botElement.querySelector('.raw-message');
mdMessage = botElement.querySelector('.md-message');
if (!rawMessage) {
var buttons = botElement.querySelectorAll('button.chuanhu-btn');
for (var i = 0; i < buttons.length; i++) {
buttons[i].parentNode.removeChild(buttons[i]);
}
return;
}
var copyButton = null;
var toggleButton = null;
copyButton = botElement.querySelector('button.copy-bot-btn');
toggleButton = botElement.querySelector('button.toggle-md-btn');
if (copyButton) copyButton.remove();
if (toggleButton) toggleButton.remove();
// Copy bot button
var copyButton = document.createElement('button');
copyButton.classList.add('chuanhu-btn');
copyButton.classList.add('copy-bot-btn');
copyButton.setAttribute('aria-label', 'Copy');
copyButton.innerHTML = copyIcon;
copyButton.addEventListener('click', () => {
const textToCopy = rawMessage.innerText;
navigator.clipboard
.writeText(textToCopy)
.then(() => {
copyButton.innerHTML = copiedIcon;
setTimeout(() => {
copyButton.innerHTML = copyIcon;
}, 1500);
})
.catch(() => {
console.error("copy failed");
});
});
botElement.appendChild(copyButton);
// Toggle button
var toggleButton = document.createElement('button');
toggleButton.classList.add('chuanhu-btn');
toggleButton.classList.add('toggle-md-btn');
toggleButton.setAttribute('aria-label', 'Toggle');
var renderMarkdown = mdMessage.classList.contains('hideM');
toggleButton.innerHTML = renderMarkdown ? mdIcon : rawIcon;
toggleButton.addEventListener('click', () => {
renderMarkdown = mdMessage.classList.contains('hideM');
if (renderMarkdown){
renderMarkdownText(botElement);
toggleButton.innerHTML=rawIcon;
} else {
removeMarkdownText(botElement);
toggleButton.innerHTML=mdIcon;
}
});
botElement.insertBefore(toggleButton, copyButton);
}
function renderMarkdownText(message) {
var mdDiv = message.querySelector('.md-message');
if (mdDiv) mdDiv.classList.remove('hideM');
var rawDiv = message.querySelector('.raw-message');
if (rawDiv) rawDiv.classList.add('hideM');
}
function removeMarkdownText(message) {
var rawDiv = message.querySelector('.raw-message');
if (rawDiv) rawDiv.classList.remove('hideM');
var mdDiv = message.querySelector('.md-message');
if (mdDiv) mdDiv.classList.add('hideM');
}
let timeoutId;
let isThrottled = false;
var mmutation
// 监听所有元素中 bot message 的变化,为 bot 消息添加复制按钮。
var mObserver = new MutationObserver(function (mutationsList) {
for (mmutation of mutationsList) {
if (mmutation.type === 'childList') {
for (var node of mmutation.addedNodes) {
if (node.nodeType === 1 && node.classList.contains('message') && node.getAttribute('data-testid') === 'bot') {
saveHistoryHtml();
document.querySelectorAll('#废弃>.wrap>.message-wrap .message.bot').forEach(addChuanhuButton);
}
if (node.tagName === 'INPUT' && node.getAttribute('type') === 'range') {
setSlider();
}
}
for (var node of mmutation.removedNodes) {
if (node.nodeType === 1 && node.classList.contains('message') && node.getAttribute('data-testid') === 'bot') {
saveHistoryHtml();
document.querySelectorAll('#废弃>.wrap>.message-wrap .message.bot').forEach(addChuanhuButton);
}
}
} else if (mmutation.type === 'attributes') {
if (mmutation.target.nodeType === 1 && mmutation.target.classList.contains('message') && mmutation.target.getAttribute('data-testid') === 'bot') {
if (isThrottled) break; // 为了防止重复不断疯狂渲染加上等待_(:з」∠)_
isThrottled = true;
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
isThrottled = false;
document.querySelectorAll('#废弃>.wrap>.message-wrap .message.bot').forEach(addChuanhuButton);
saveHistoryHtml();
}, 500);
}
}
}
});
mObserver.observe(document.documentElement, { attributes: true, childList: true, subtree: true });
// 监视页面内部 DOM 变动
var observer = new MutationObserver(function (mutations) {
gradioLoaded(mutations);
});
observer.observe(targetNode, { childList: true, subtree: true });
// 监视页面变化
window.addEventListener("DOMContentLoaded", function () {
isInIframe = (window.self !== window.top);
historyLoaded = false;
});
window.addEventListener('resize', setChatbotHeight);
window.addEventListener('scroll', setChatbotHeight);
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", adjustDarkMode);
// button svg code
const copyIcon = '<span><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height=".8em" width=".8em" xmlns="http://www.w3.org/2000/svg"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></span>';
const copiedIcon = '<span><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height=".8em" width=".8em" xmlns="http://www.w3.org/2000/svg"><polyline points="20 6 9 17 4 12"></polyline></svg></span>';
const mdIcon = '<span><svg stroke="currentColor" fill="none" stroke-width="1" viewBox="0 0 14 18" stroke-linecap="round" stroke-linejoin="round" height=".8em" width=".8em" xmlns="http://www.w3.org/2000/svg"><g transform-origin="center" transform="scale(0.85)"><path d="M1.5,0 L12.5,0 C13.3284271,-1.52179594e-16 14,0.671572875 14,1.5 L14,16.5 C14,17.3284271 13.3284271,18 12.5,18 L1.5,18 C0.671572875,18 1.01453063e-16,17.3284271 0,16.5 L0,1.5 C-1.01453063e-16,0.671572875 0.671572875,1.52179594e-16 1.5,0 Z" stroke-width="1.8"></path><line x1="3.5" y1="3.5" x2="10.5" y2="3.5"></line><line x1="3.5" y1="6.5" x2="8" y2="6.5"></line></g><path d="M4,9 L10,9 C10.5522847,9 11,9.44771525 11,10 L11,13.5 C11,14.0522847 10.5522847,14.5 10,14.5 L4,14.5 C3.44771525,14.5 3,14.0522847 3,13.5 L3,10 C3,9.44771525 3.44771525,9 4,9 Z" stroke="none" fill="currentColor"></path></svg></span>';
const rawIcon = '<span><svg stroke="currentColor" fill="none" stroke-width="1.8" viewBox="0 0 18 14" stroke-linecap="round" stroke-linejoin="round" height=".8em" width=".8em" xmlns="http://www.w3.org/2000/svg"><g transform-origin="center" transform="scale(0.85)"><polyline points="4 3 0 7 4 11"></polyline><polyline points="14 3 18 7 14 11"></polyline><line x1="12" y1="0" x2="6" y2="14"></line></g></svg></span>';

View File

@ -0,0 +1,2 @@
// external javascript here

View File

@ -0,0 +1,8 @@
<div style="display: flex; justify-content: space-between;">
<span>
<label class="apSwitch" for="checkbox">
<input type="checkbox" id="checkbox">
<div class="apSlider"></div>
</label>
</span>
</div>

View File

@ -0,0 +1,9 @@
<b>{label}</b>
<div class="progress-bar">
<div class="progress" style="width: {usage_percent}%;">
<span class="progress-text">{usage_percent}%</span>
</div>
</div>
<div style="display: flex; justify-content: space-between;">
<span>${rounded_usage}</span><span>${usage_limit}</span>
</div>

View File

@ -0,0 +1 @@
<div class="versions">{versions}</div>

BIN
docs/imgs/pic_desc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -49,7 +49,7 @@ def markdown_convertion(txt):
"""
将Markdown格式的文本转换为HTML格式。如果包含数学公式则先将公式转换为HTML格式。
"""
pre = '<div class="markdown-body">'
pre = '<div class="md-message">'
suf = '</div>'
if txt.startswith(pre) and txt.endswith(suf):
# print('警告,输入了已经经过转化的字符串,二次转化可能出问题')

View File

@ -265,7 +265,7 @@
"例如chatglm&gpt-3.5-turbo&api2d-gpt-4": "e.g. chatglm&gpt-3.5-turbo&api2d-gpt-4",
"先切换模型到openai或api2d": "Switch the model to openai or api2d first",
"在这里输入分辨率": "Enter the resolution here",
"如256x256": "e.g. 256x256",
"如'256x256', '512x512', '1024x1024'": "e.g. '256x256', '512x512', '1024x1024'",
"默认": "Default",
"建议您复制一个config_private.py放自己的秘密": "We suggest you to copy a config_private.py file to keep your secrets, such as API and proxy URLs, from being accidentally uploaded to Github and seen by others.",
"如API和代理网址": "Such as API and proxy URLs",

View File

@ -12,7 +12,7 @@ try {
live2d_settings['waifuTipsSize'] = '187x52';
live2d_settings['canSwitchModel'] = true;
live2d_settings['canSwitchTextures'] = true;
live2d_settings['canSwitchHitokoto'] = false;
live2d_settings['canSwitchHitokoto'] = true;
live2d_settings['canTakeScreenshot'] = false;
live2d_settings['canTurnToHomePage'] = false;
live2d_settings['canTurnToAboutPage'] = false;

View File

@ -34,10 +34,10 @@
"2": ["来自 Potion Maker 的 Tia 酱 ~"]
},
"hitokoto_api_message": {
"lwl12.com": ["这句一言来自 <span style=\"color:#0099cc;\">『{source}』</span>", ",是 <span style=\"color:#0099cc;\">{creator}</span> 投稿的", "。"],
"fghrsh.net": ["这句一言出处是 <span style=\"color:#0099cc;\">『{source}』</span>,是 <span style=\"color:#0099cc;\">FGHRSH</span> 在 {date} 收藏的!"],
"jinrishici.com": ["这句诗词出自 <span style=\"color:#0099cc;\">《{title}》</span>,是 {dynasty}诗人 {author} 创作的!"],
"hitokoto.cn": ["这句一言来自 <span style=\"color:#0099cc;\">『{source}』</span>,是 <span style=\"color:#0099cc;\">{creator}</span> 在 hitokoto.cn 投稿的。"]
"lwl12.com": ["这句一言来自 <span style=\"color:#ff99da;\">『{source}』</span>", ",是 <span style=\"color:#ff99da;\">{creator}</span> 投稿的", "。"],
"fghrsh.net": ["这句一言出处是 <span style=\"color:#ff99da;\">『{source}』</span>,是 <span style=\"color:#ff99da;\">FGHRSH</span> 在 {date} 收藏的!"],
"jinrishici.com": ["这句诗词出自 <span style=\"color:#ff99da;\">《{title}》</span>,是 {dynasty}诗人 {author} 创作的!"],
"hitokoto.cn": ["这句一言来自 <span style=\"color:#ff99da;\">『{source}』</span>,是 <span style=\"color:#ff99da;\">{creator}</span> 在 hitokoto.cn 投稿的。"]
}
},
"mouseover": [

778
func_box.py Normal file
View File

@ -0,0 +1,778 @@
#! .\venv\
# encoding: utf-8
# @Time : 2023/4/18
# @Author : Spike
# @Descr :
import ast
import copy
import hashlib
import io
import json
import os.path
import subprocess
import threading
import time
from concurrent.futures import ThreadPoolExecutor
import Levenshtein
import psutil
import re
import tempfile
import shutil
from contextlib import ExitStack
import logging
import yaml
import requests
import tiktoken
logger = logging
from sklearn.feature_extraction.text import CountVectorizer
import numpy as np
from scipy.linalg import norm
import pyperclip
import random
import gradio as gr
import toolbox
from prompt_generator import SqliteHandle
from bs4 import BeautifulSoup
import copy
"""contextlib 是 Python 标准库中的一个模块,提供了一些工具函数和装饰器,用于支持编写上下文管理器和处理上下文的常见任务,例如资源管理、异常处理等。
官网https://docs.python.org/3/library/contextlib.html"""
class Shell(object):
def __init__(self, args, stream=False):
self.args = args
self.subp = subprocess.Popen(args, shell=True,
stdin=subprocess.PIPE, stderr=subprocess.PIPE,
stdout=subprocess.PIPE, encoding='utf-8',
errors='ignore', close_fds=True)
self.__stream = stream
self.__temp = ''
def read(self):
logger.debug(f'The command being executed is: "{self.args}"')
if self.__stream:
sysout = self.subp.stdout
try:
with sysout as std:
for i in std:
logger.info(i.rstrip())
self.__temp += i
except KeyboardInterrupt as p:
return 3, self.__temp + self.subp.stderr.read()
finally:
return 3, self.__temp + self.subp.stderr.read()
else:
sysout = self.subp.stdout.read()
syserr = self.subp.stderr.read()
self.subp.stdin
if sysout:
logger.debug(f"{self.args} \n{sysout}")
return 1, sysout
elif syserr:
logger.error(f"{self.args} \n{syserr}")
return 0, syserr
else:
logger.debug(f"{self.args} \n{[sysout], [sysout]}")
return 2, '\n{}\n{}'.format(sysout, sysout)
def sync(self):
logger.debug('The command being executed is: "{}"'.format(self.args))
for i in self.subp.stdout:
logger.debug(i.rstrip())
self.__temp += i
yield self.__temp
for i in self.subp.stderr:
logger.debug(i.rstrip())
self.__temp += i
yield self.__temp
def timeStatistics(func):
"""
统计函数执行时常的装饰器
"""
def statistics(*args, **kwargs):
startTiem = time.time()
obj = func(*args, **kwargs)
endTiem = time.time()
ums = startTiem - endTiem
print('func:{} > Time-consuming: {}'.format(func, ums))
return obj
return statistics
def copy_temp_file(file):
if os.path.exists(file):
exdir = tempfile.mkdtemp()
temp_ = shutil.copy(file, os.path.join(exdir, os.path.basename(file)))
return temp_
else:
return None
def md5_str(st):
# 创建一个 MD5 对象
md5 = hashlib.md5()
# 更新 MD5 对象的内容
md5.update(str(st).encode())
# 获取加密后的结果
result = md5.hexdigest()
return result
def html_tag_color(tag, color=None, font='black'):
"""
将文本转换为带有高亮提示的html代码
"""
if not color:
rgb = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
color = f"rgb{rgb}"
tag = f'<span style="background-color: {color}; font-weight: bold; color: {font}">&nbsp;{tag}&ensp;</span>'
return tag
def html_a_blank(__href, name=''):
if not name:
name = __href
a = f'<a href="{__href}" target="_blank" class="svelte-xrr240">{name}</a>'
return a
def html_view_blank(__href, file_name=''):
if os.path.exists(__href):
__href = f'/file={__href}'
if not file_name:
file_name = __href.split('/')[-1]
a = f'<a href="{__href}" target="_blank" class="svelte-xrr240">{file_name}</a>'
return a
def html_iframe_code(html_file):
proxy, = toolbox.get_conf('LOCAL_PORT')
html_file = f'http://{ipaddr()}:{proxy}/file={html_file}'
ifr = f'<iframe width="100%" height="500px" frameborder="0" src="{html_file}"></iframe>'
return ifr
def html_download_blank(__href, file_name='temp', dir_name=''):
if os.path.exists(__href):
__href = f'/file={__href}'
if not dir_name:
dir_name = file_name
a = f'<a href="{__href}" target="_blank" download="{dir_name}" class="svelte-xrr240">{file_name}</a>'
return a
def html_local_img(__file):
a = f'<div align="center"><img src="file={__file}"></div>'
return a
def ipaddr():
# 获取本地ipx
ip = psutil.net_if_addrs()
for i in ip:
if ip[i][0][3]:
return ip[i][0][1]
def encryption_str(txt: str):
"""(关键字)(加密间隔)匹配机制(关键字间隔)"""
txt = str(txt)
pattern = re.compile(rf"(Authorization|WPS-Sid|Cookie)(:|\s+)\s*(\S+)[\s\S]*?(?=\n|$|\s)", re.IGNORECASE)
result = pattern.sub(lambda x: x.group(1) + ": XXXXXXXX", txt)
return result
def tree_out(dir=os.path.dirname(__file__), line=2, more=''):
"""
获取本地文件的树形结构转化为Markdown代码文本
"""
out = Shell(f'tree {dir} -F -I "__*|.*|venv|*.png|*.xlsx" -L {line} {more}').read()[1]
localfile = os.path.join(os.path.dirname(__file__), '.tree.md')
with open(localfile, 'w') as f:
f.write('```\n')
ll = out.splitlines()
for i in range(len(ll)):
if i == 0:
f.write(ll[i].split('/')[-2] + '\n')
else:
f.write(ll[i] + '\n')
f.write('```\n')
def chat_history(log: list, split=0):
"""
auto_gpt 使用的代码,后续会迁移
"""
if split:
log = log[split:]
chat = ''
history = ''
for i in log:
chat += f'{i[0]}\n\n'
history += f'{i[1]}\n\n'
return chat, history
def df_similarity(s1, s2):
"""弃用,会警告,这个库不会用"""
def add_space(s):
return ' '.join(list(s))
# 将字中间加入空格
s1, s2 = add_space(s1), add_space(s2)
# 转化为TF矩阵
cv = CountVectorizer(tokenizer=lambda s: s.split())
corpus = [s1, s2]
vectors = cv.fit_transform(corpus).toarray()
# 计算TF系数
return np.dot(vectors[0], vectors[1]) / (norm(vectors[0]) * norm(vectors[1]))
def check_json_format(file):
"""
检查上传的Json文件是否符合规范
"""
new_dict = {}
data = JsonHandle(file).load()
if type(data) is list and len(data) > 0:
if type(data[0]) is dict:
for i in data:
new_dict.update({i['act']: i['prompt']})
return new_dict
def json_convert_dict(file):
"""
批量将json转换为字典
"""
new_dict = {}
for root, dirs, files in os.walk(file):
for f in files:
if f.startswith('prompt') and f.endswith('json'):
new_dict.update(check_json_format(f))
return new_dict
def draw_results(txt, prompt: gr.Dataset, percent, switch, ipaddr: gr.Request):
"""
绘制搜索结果
Args:
txt (str): 过滤文本
prompt : 原始的dataset对象
percent (int): TF系数用于计算文本相似度
switch (list): 过滤个人或所有人的Prompt
ipaddr : 请求人信息
Returns:
注册函数所需的元祖对象
"""
data = diff_list(txt, percent=percent, switch=switch, hosts=ipaddr.client.host)
prompt.samples = data
return prompt.update(samples=data, visible=True), prompt
def diff_list(txt='', percent=0.70, switch: list = None, lst: dict = None, sp=15, hosts=''):
"""
按照搜索结果统计相似度的文本,两组文本相似度>70%的将统计在一起取最长的作为key
Args:
txt (str): 过滤文本
percent (int): TF系数用于计算文本相似度
switch (list): 过滤个人或所有人的Prompt
lst指定一个列表或字典
sp: 截取展示的文本长度
hosts : 请求人的ip
Returns:
返回一个列表
"""
count_dict = {}
is_all = toolbox.get_conf('prompt_list')[0]['key'][1]
if not lst:
lst = {}
tabs = SqliteHandle().get_tables()
if is_all in switch:
lst.update(SqliteHandle(f"ai_common_{hosts}").get_prompt_value(txt))
else:
for tab in tabs:
if tab.startswith('ai_common'):
lst.update(SqliteHandle(f"{tab}").get_prompt_value(txt))
lst.update(SqliteHandle(f"ai_private_{hosts}").get_prompt_value(txt))
# diff 数据根据precent系数归类数据
str_ = time.time()
def tf_factor_calcul(i):
found = False
dict_copy = count_dict.copy()
for key in dict_copy.keys():
str_tf = Levenshtein.jaro_winkler(i, key)
if str_tf >= percent:
if len(i) > len(key):
count_dict[i] = count_dict.copy()[key] + 1
count_dict.pop(key)
else:
count_dict[key] += 1
found = True
break
if not found: count_dict[i] = 1
with ThreadPoolExecutor(100) as executor:
executor.map(tf_factor_calcul, lst)
print('计算耗时', time.time()-str_)
sorted_dict = sorted(count_dict.items(), key=lambda x: x[1], reverse=True)
if switch:
sorted_dict += prompt_retrieval(is_all=switch, hosts=hosts, search=True)
dateset_list = []
for key in sorted_dict:
# 开始匹配关键字
index = str(key[0]).lower().find(txt.lower())
index_ = str(key[1]).lower().find(txt.lower())
if index != -1 or index_ != -1:
if index == -1: index = index_ # 增加搜索prompt 名称
# sp=split 用于判断在哪里启动、在哪里断开
if index - sp > 0:
start = index - sp
else:
start = 0
if len(key[0]) > sp * 2:
end = key[0][-sp:]
else:
end = ''
# 判断有没有传需要匹配的字符串,有则筛选、无则全返
if txt == '' and len(key[0]) >= sp:
show = key[0][0:sp] + " . . . " + end
show = show.replace('<', '')
elif txt == '' and len(key[0]) < sp:
show = key[0][0:sp]
show = show.replace('<', '')
else:
show = str(key[0][start:index + sp]).replace('<', '').replace(txt, html_tag_color(txt))
show += f" {html_tag_color(' X ' + str(key[1]))}"
if lst.get(key[0]):
be_value = lst[key[0]]
else:
be_value = None
value = be_value
dateset_list.append([show, key[0], value, key[1]])
return dateset_list
def prompt_upload_refresh(file, prompt, ipaddr: gr.Request):
"""
上传文件将文件转换为字典然后存储到数据库并刷新Prompt区域
Args:
file 上传的文件
prompt 原始prompt对象
ipaddripaddr用户请求信息
Returns:
注册函数所需的元祖对象
"""
hosts = ipaddr.client.host
if file.name.endswith('json'):
upload_data = check_json_format(file.name)
elif file.name.endswith('yaml'):
upload_data = YamlHandle(file.name).load()
else:
upload_data = {}
if upload_data != {}:
SqliteHandle(f'prompt_{hosts}').inset_prompt(upload_data)
ret_data = prompt_retrieval(is_all=['个人'], hosts=hosts)
return prompt.update(samples=ret_data, visible=True), prompt, ['个人']
else:
prompt.samples = [[f'{html_tag_color("数据解析失败,请检查文件是否符合规范", color="red")}', '']]
return prompt.samples, prompt, []
def prompt_retrieval(is_all, hosts='', search=False):
"""
上传文件将文件转换为字典然后存储到数据库并刷新Prompt区域
Args:
is_all prompt类型
hosts 查询的用户ip
search支持搜索搜索时将key作为key
Returns:
返回一个列表
"""
count_dict = {}
if '所有人' in is_all:
for tab in SqliteHandle('ai_common').get_tables():
if tab.startswith('prompt'):
data = SqliteHandle(tab).get_prompt_value(None)
if data: count_dict.update(data)
elif '个人' in is_all:
data = SqliteHandle(f'prompt_{hosts}').get_prompt_value(None)
if data: count_dict.update(data)
retrieval = []
if count_dict != {}:
for key in count_dict:
if not search:
retrieval.append([key, count_dict[key]])
else:
retrieval.append([count_dict[key], key])
return retrieval
else:
return retrieval
def prompt_reduce(is_all, prompt: gr.Dataset, ipaddr: gr.Request): # is_all, ipaddr: gr.Request
"""
上传文件将文件转换为字典然后存储到数据库并刷新Prompt区域
Args:
is_all prompt类型
prompt dataset原始对象
ipaddr请求用户信息
Returns:
返回注册函数所需的对象
"""
data = prompt_retrieval(is_all=is_all, hosts=ipaddr.client.host)
prompt.samples = data
return prompt.update(samples=data, visible=True), prompt, is_all
def prompt_save(txt, name, prompt: gr.Dataset, ipaddr: gr.Request):
"""
编辑和保存Prompt
Args:
txt Prompt正文
name Prompt的名字
prompt dataset原始对象
ipaddr请求用户信息
Returns:
返回注册函数所需的对象
"""
if txt and name:
yaml_obj = SqliteHandle(f'prompt_{ipaddr.client.host}')
yaml_obj.inset_prompt({name: txt})
result = prompt_retrieval(is_all=['个人'], hosts=ipaddr.client.host)
prompt.samples = result
return "", "", ['个人'], prompt.update(samples=result, visible=True), prompt, gr.Tabs.update(selected='chatbot')
elif not txt or not name:
result = [[f'{html_tag_color("编辑框 or 名称不能为空!!!!!", color="red")}', '']]
prompt.samples = [[f'{html_tag_color("编辑框 or 名称不能为空!!!!!", color="red")}', '']]
return txt, name, [], prompt.update(samples=result, visible=True), prompt, gr.Tabs.update(selected='chatbot')
def prompt_input(txt: str, prompt_str, name_str, index, data: gr.Dataset, tabs_index):
"""
点击dataset的值使用Prompt
Args:
txt 输入框正文
index 点击的Dataset下标
data dataset原始对象
Returns:
返回注册函数所需的对象
"""
data_str = str(data.samples[index][1])
data_name = str(data.samples[index][0])
rp_str = '{{{v}}}'
def str_v_handle(__str):
if data_str.find(rp_str) != -1 and __str:
txt_temp = data_str.replace(rp_str, __str)
elif __str:
txt_temp = data_str + '\n' + __str
else:
txt_temp = data_str
return txt_temp
if tabs_index == 1:
new_txt = str_v_handle(prompt_str)
return txt, new_txt, data_name
else:
new_txt = str_v_handle(txt)
return new_txt, prompt_str, name_str
def copy_result(history):
"""复制history"""
if history != []:
pyperclip.copy(history[-1])
return '已将结果复制到剪切板'
else:
return "无对话记录,复制错误!!"
def str_is_list(s):
try:
list_ast = ast.literal_eval(s)
return isinstance(list_ast, list)
except (SyntaxError, ValueError):
return False
def show_prompt_result(index, data: gr.Dataset, chatbot, pro_edit, pro_name):
"""
查看Prompt的对话记录结果
Args:
index 点击的Dataset下标
data dataset原始对象
chatbot聊天机器人
Returns:
返回注册函数所需的对象
"""
click = data.samples[index]
if str_is_list(click[2]):
list_copy = eval(click[2])
for i in range(0, len(list_copy), 2):
if i + 1 >= len(list_copy): # 如果下标越界了,单独处理最后一个元素
chatbot.append([list_copy[i]])
else:
chatbot.append([list_copy[i], list_copy[i + 1]])
elif click[2] is None and pro_edit == '':
pro_edit = click[1]
pro_name = click[3]
else:
chatbot.append((click[1], click[2]))
return chatbot, pro_edit, pro_name
def pattern_html(html):
bs = BeautifulSoup(str(html), 'html.parser')
md_message = bs.find('div', {'class': 'md-message'})
if md_message:
return md_message.get_text(separator='')
else:
return ""
def thread_write_chat(chatbot, history):
"""
对话记录写入数据库
"""
chatbot, history = copy.copy(chatbot), copy.copy(history)
private_key = toolbox.get_conf('private_key')[0]
chat_title = chatbot[0][1].split()
i_say = pattern_html(chatbot[-1][0])
if history:
gpt_result = history
else: # 如果历史对话不存在,那么读取对话框
gpt_result = [pattern_html(v) for i in chatbot for v in i]
if private_key in chat_title:
SqliteHandle(f'ai_private_{chat_title[-2]}').inset_prompt({i_say: gpt_result})
else:
SqliteHandle(f'ai_common_{chat_title[-2]}').inset_prompt({i_say: gpt_result})
base_path = os.path.dirname(__file__)
prompt_path = os.path.join(base_path, 'users_data')
users_path = os.path.join(base_path, 'private_upload')
logs_path = os.path.join(base_path, 'gpt_log')
def reuse_chat(result, chatbot, history, pro_numb, say):
"""复用对话记录"""
if result is None or result == []:
return chatbot, history, gr.update(), gr.update(), '', gr.Column.update()
else:
if pro_numb:
chatbot += result
history += [pattern_html(_) for i in result for _ in i]
else:
chatbot.append(result[-1])
history += [pattern_html(_) for i in result[-2:] for _ in i]
print(chatbot[-1][0])
return chatbot, history, say, gr.Tabs.update(selected='chatbot'), '', gr.Column.update(visible=False)
def num_tokens_from_string(listing: list, encoding_name: str = 'cl100k_base') -> int:
"""Returns the number of tokens in a text string."""
count_tokens = 0
for i in listing:
encoding = tiktoken.get_encoding(encoding_name)
count_tokens += len(encoding.encode(i))
return count_tokens
def spinner_chatbot_loading(chatbot):
loading = [''.join(['.' * random.randint(1, 5)])]
# 将元组转换为列表并修改元素
loading_msg = copy.deepcopy(chatbot)
temp_list = list(loading_msg[-1])
temp_list[1] = pattern_html(temp_list[1]) + f'{random.choice(loading)}'
# 将列表转换回元组并替换原始元组
loading_msg[-1] = tuple(temp_list)
return loading_msg
def refresh_load_data(chat, history, prompt, crazy_list, request: gr.Request):
"""
Args:
chat: 聊天组件
history: 对话记录
prompt: prompt dataset组件
Returns:
预期是每次刷新页面,加载最新
"""
is_all = toolbox.get_conf('prompt_list')[0]['key'][0]
data = prompt_retrieval(is_all=[is_all])
prompt.samples = data
selected = random.sample(crazy_list, 4)
user_agent = request.kwargs['headers']['user-agent'].lower()
if user_agent.find('android') != -1 or user_agent.find('iphone') != -1:
hied_elem = gr.update(visible=False)
else:
hied_elem = gr.update()
outputs = [prompt.update(samples=data, visible=True), prompt,
chat, history, gr.Dataset.update(samples=[[i] for i in selected]), selected,
hied_elem, hied_elem]
return outputs
def txt_converter_json(input_string):
try:
if input_string.startswith("{") and input_string.endswith("}"):
# 尝试将字符串形式的字典转换为字典对象
dict_object = ast.literal_eval(input_string)
else:
# 尝试将字符串解析为JSON对象
dict_object = json.loads(input_string)
formatted_json_string = json.dumps(dict_object, indent=4, ensure_ascii=False)
return formatted_json_string
except (ValueError, SyntaxError):
return input_string
def clean_br_string(s):
s = re.sub('<\s*br\s*/?>', '\n', s) # 使用正则表达式同时匹配<br>、<br/>、<br />、< br>和< br/>
return s
def update_btn(self,
value: str = None,
variant: str = None,
visible: bool = None,
interactive: bool = None,
elem_id: str = None,
label: str = None
):
if not variant: variant = self.variant
if not visible: visible = self.visible
if not value: value = self.value
if not interactive: interactive = self.interactive
if not elem_id: elem_id = self.elem_id
if not elem_id: label = self.label
return {
"variant": variant,
"visible": visible,
"value": value,
"interactive": interactive,
'elem_id': elem_id,
'label': label,
"__type__": "update",
}
def update_txt(self,
value: str = None,
lines: int = None,
max_lines: int = None,
placeholder: str = None,
label: str = None,
show_label: bool = None,
visible: bool = None,
interactive: bool = None,
type: str = None,
elem_id: str = None
):
return {
"lines": self.lines,
"max_lines": self.max_lines,
"placeholder": self.placeholder,
"label": self.label,
"show_label": self.show_label,
"visible": self.visible,
"value": self.value,
"type": self.type,
"interactive": self.interactive,
"elem_id": elem_id,
"__type__": "update",
}
def get_html(filename):
path = os.path.join(base_path, "docs/assets", "html", filename)
if os.path.exists(path):
with open(path, encoding="utf8") as file:
return file.read()
return ""
def git_log_list():
ll = Shell("git log --pretty=format:'%s | %h' -n 10").read()[1].splitlines()
return [i.split('|') for i in ll if 'branch' not in i][:5]
import qrcode
from PIL import Image, ImageDraw
def qr_code_generation(data, icon_path=None, file_name='qc_icon.png'):
# 创建qrcode对象
qr = qrcode.QRCode(version=2, error_correction=qrcode.constants.ERROR_CORRECT_Q, box_size=10, border=2,)
qr.add_data(data)
# 创建二维码图片
img = qr.make_image()
# 图片转换为RGBA格式
img = img.convert('RGBA')
# 返回二维码图片的大小
img_w, img_h = img.size
# 打开logo
if not icon_path:
icon_path = os.path.join(base_path, 'docs/assets/PLAI.jpeg')
logo = Image.open(icon_path)
# logo大小为二维码的四分之一
logo_w = img_w // 4
logo_h = img_w // 4
# 修改logo图片大小
logo = logo.resize((logo_w, logo_h), Image.LANCZOS) # or Image.Resampling.LANCZOS
# 把logo放置在二维码中间
w = (img_w - logo_w) // 2
h = (img_h - logo_h) // 2
img.paste(logo, (w, h))
qr_path = os.path.join(logs_path, 'file_name')
img.save()
return qr_path
class YamlHandle:
def __init__(self, file=os.path.join(prompt_path, 'ai_common.yaml')):
if not os.path.exists(file):
Shell(f'touch {file}').read()
self.file = file
self._load = self.load()
def load(self) -> dict:
with open(file=self.file, mode='r') as f:
data = yaml.safe_load(f)
return data
def update(self, key, value):
date = self._load
if not date:
date = {}
date[key] = value
with open(file=self.file, mode='w') as f:
yaml.dump(date, f, allow_unicode=True)
return date
def dump_dict(self, new_dict):
date = self._load
if not date:
date = {}
date.update(new_dict)
with open(file=self.file, mode='w') as f:
yaml.dump(date, f, allow_unicode=True)
return date
class JsonHandle:
def __init__(self, file):
self.file = file
def load(self) -> object:
with open(self.file, 'r') as f:
data = json.load(f)
return data
if __name__ == '__main__':
pass

View File

@ -130,9 +130,9 @@ def main():
ret.update({plugin_advanced_arg: gr.update(visible=("插件参数区" in a))})
if "底部输入区" in a: ret.update({txt: gr.update(value="")})
return ret
checkboxes.select(fn_area_visibility, [checkboxes], [area_basic_fn, area_crazy_fn, area_input_primary, area_input_secondary, txt, txt2, clearBtn, clearBtn2, plugin_advanced_arg] )
checkboxes.select(fn_area_visibility, [checkboxes], [area_basic_fn, area_crazy_fn, area_input_primary, area_input_secondary, txt, clearBtn, clearBtn2, plugin_advanced_arg] )
# 整理反复出现的控件句柄组合
input_combo = [cookies, max_length_sl, md_dropdown, txt, txt2, top_p, temperature, chatbot, history, system_prompt, plugin_advanced_arg]
input_combo = [cookies, max_length_sl, md_dropdown, txt, top_p, temperature, chatbot, history, system_prompt, plugin_advanced_arg]
output_combo = [cookies, chatbot, history, status]
predict_args = dict(fn=ArgsGeneralWrapper(predict), inputs=input_combo, outputs=output_combo)
# 提交按钮、重置按钮
@ -155,7 +155,7 @@ def main():
click_handle = functional[k]["Button"].click(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True), gr.State(k)], outputs=output_combo)
cancel_handles.append(click_handle)
# 文件上传区接收文件后与chatbot的互动
file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt, txt2, checkboxes], [chatbot, txt, txt2])
file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt ], [chatbot, txt])
# 函数插件-固定按钮区
for k in crazy_fns:
if not crazy_fns[k].get("AsButton", True): continue
@ -174,7 +174,7 @@ def main():
dropdown.select(on_dropdown_changed, [dropdown], [switchy_bt, plugin_advanced_arg] )
def on_md_dropdown_changed(k):
return {chatbot: gr.update(label="当前模型:"+k)}
md_dropdown.select(on_md_dropdown_changed, [md_dropdown], [chatbot] )
md_dropdown.select(on_md_dropdown_changed, [md_dropdown], [chatbot])
# 随变按钮的回调函数注册
def route(k, *args, **kwargs):
if k in [r"打开插件列表", r"请先从插件列表中选择"]: return

102
prompt_generator.py Normal file
View File

@ -0,0 +1,102 @@
#! .\venv\
# encoding: utf-8
# @Time : 2023/4/19
# @Author : Spike
# @Descr :
import os.path
import sqlite3
import threading
import functools
import func_box
# 连接到数据库
base_path = os.path.dirname(__file__)
prompt_path = os.path.join(base_path, 'users_data')
def connect_db_close(cls_method):
@functools.wraps(cls_method)
def wrapper(cls=None, *args, **kwargs):
cls._connect_db()
result = cls_method(cls, *args, **kwargs)
cls._close_db()
return result
return wrapper
class SqliteHandle:
def __init__(self, table='ai_common', database='ai_prompt.db'):
self.__database = database
self.__connect = sqlite3.connect(os.path.join(prompt_path, self.__database))
self.__cursor = self.__connect.cursor()
self.__table = table
if self.__table not in self.get_tables():
self.create_tab()
def new_connect_db(self):
"""多线程操作时每个线程新建独立的connect"""
self.__connect = sqlite3.connect(os.path.join(prompt_path, self.__database))
self.__cursor = self.__connect.cursor()
def new_close_db(self):
self.__cursor.close()
self.__connect.close()
def create_tab(self):
self.__cursor.execute(f"CREATE TABLE `{self.__table}` ('prompt' TEXT UNIQUE, 'result' TEXT)")
def get_tables(self):
all_tab = []
result = self.__cursor.execute("SELECT name FROM sqlite_master WHERE type = 'table';")
for tab in result:
all_tab.append(tab[0])
return all_tab
def get_prompt_value(self, find=None):
temp_all = {}
if find:
result = self.__cursor.execute(f"SELECT prompt, result FROM `{self.__table}` WHERE prompt LIKE '%{find}%'").fetchall()
else:
result = self.__cursor.execute(f"SELECT prompt, result FROM `{self.__table}`").fetchall()
for row in result:
temp_all[row[0]] = row[1]
return temp_all
def inset_prompt(self, prompt: dict):
for key in prompt:
self.__cursor.execute(f"REPLACE INTO `{self.__table}` (prompt, result) VALUES (?, ?);", (str(key), str(prompt[key])))
self.__connect.commit()
def delete_prompt(self, name):
self.__cursor.execute(f"DELETE from `{self.__table}` where prompt LIKE '{name}'")
self.__connect.commit()
def delete_tabls(self, tab):
self.__cursor.execute(f"DROP TABLE `{tab}`;")
self.__connect.commit()
def find_prompt_result(self, name):
query = self.__cursor.execute(f"SELECT result FROM `{self.__table}` WHERE prompt LIKE '{name}'").fetchall()
if query == []:
query = self.__cursor.execute(f"SELECT result FROM `prompt_127.0.0.1` WHERE prompt LIKE '{name}'").fetchall()
return query[0][0]
else:
return query[0][0]
def cp_db_data(incloud_tab='prompt'):
sql_ll = sqlite_handle(database='ai_prompt_cp.db')
tabs = sql_ll.get_tables()
for i in tabs:
if str(i).startswith(incloud_tab):
old_data = sqlite_handle(table=i, database='ai_prompt_cp.db').get_prompt_value()
sqlite_handle(table=i).inset_prompt(old_data)
def inset_127_prompt():
sql_handle = sqlite_handle(table='prompt_127.0.0.1')
prompt_json = os.path.join(prompt_path, 'prompts-PlexPt.json')
data_list = func_box.JsonHandle(prompt_json).load()
for i in data_list:
sql_handle.inset_prompt(prompt={i['act']: i['prompt']})
sqlite_handle = SqliteHandle
if __name__ == '__main__':
cp_db_data()

View File

@ -13,8 +13,11 @@ from functools import lru_cache
from concurrent.futures import ThreadPoolExecutor
from toolbox import get_conf, trimmed_format_exc
from .bridge_chatgpt import predict_no_ui_long_connection as chatgpt_noui
from .bridge_chatgpt import predict as chatgpt_ui
from request_llm.bridge_chatgpt import predict_no_ui_long_connection as chatgpt_noui
from request_llm.bridge_chatgpt import predict as chatgpt_ui
from .bridge_azure_test import predict_no_ui_long_connection as azure_noui
from .bridge_azure_test import predict as azure_ui
from .bridge_azure_test import predict_no_ui_long_connection as azure_noui
from .bridge_azure_test import predict as azure_ui
@ -51,10 +54,11 @@ class LazyloadTiktoken(object):
return encoder.decode(*args, **kwargs)
# Endpoint 重定向
API_URL_REDIRECT, = get_conf("API_URL_REDIRECT")
API_URL_REDIRECT, PROXY_API_URL = get_conf("API_URL_REDIRECT", 'PROXY_API_URL')
openai_endpoint = "https://api.openai.com/v1/chat/completions"
api2d_endpoint = "https://openai.api2d.net/v1/chat/completions"
newbing_endpoint = "wss://sydney.bing.com/sydney/ChatHub"
proxy_endpoint = PROXY_API_URL
# 兼容旧版的配置
try:
API_URL, = get_conf("API_URL")
@ -69,6 +73,7 @@ if api2d_endpoint in API_URL_REDIRECT: api2d_endpoint = API_URL_REDIRECT[api2d_e
if newbing_endpoint in API_URL_REDIRECT: newbing_endpoint = API_URL_REDIRECT[newbing_endpoint]
# 获取tokenizer
tokenizer_gpt35 = LazyloadTiktoken("gpt-3.5-turbo")
tokenizer_gpt4 = LazyloadTiktoken("gpt-4")
@ -122,6 +127,15 @@ model_info = {
"tokenizer": tokenizer_gpt4,
"token_cnt": get_token_num_gpt4,
},
# azure openai
"azure-gpt35":{
"fn_with_ui": azure_ui,
"fn_without_ui": azure_noui,
"endpoint": get_conf("AZURE_ENDPOINT"),
"max_token": 4096,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
# azure openai
"azure-gpt35":{
@ -147,9 +161,9 @@ model_info = {
"fn_with_ui": chatgpt_ui,
"fn_without_ui": chatgpt_noui,
"endpoint": api2d_endpoint,
"max_token": 8192,
"tokenizer": tokenizer_gpt4,
"token_cnt": get_token_num_gpt4,
"max_token": 4096,
"tokenizer": tokenizer_gpt35,
"token_cnt": get_token_num_gpt35,
},
# 将 chatglm 直接对齐到 chatglm2

View File

@ -12,12 +12,14 @@
"""
import json
import random
import time
import gradio as gr
import logging
import traceback
import requests
import importlib
import func_box
# config_private.py放自己的秘密如API和代理网址
# 读取时首先看是否存在私密的config_private配置文件不受git管控如果有则覆盖原config文件
@ -60,7 +62,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
while True:
try:
# make a POST request to the API endpoint, stream=False
from .bridge_all import model_info
from request_llm.bridge_all import model_info
endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
response = requests.post(endpoint, headers=headers, proxies=proxies,
json=payload, stream=True, timeout=TIMEOUT_SECONDS); break
@ -106,7 +108,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="",
return result
def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None):
def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream=True, additional_fn=None):
"""
发送至chatGPT流式获取输出。
用于基础的对话功能。
@ -134,24 +136,22 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
inputs = core_functional[additional_fn]["Prefix"] + inputs + core_functional[additional_fn]["Suffix"]
raw_input = inputs
logging.info(f'[raw_input] {raw_input}')
logging.info(f'[raw_input]_{llm_kwargs["ipaddr"]} {raw_input}')
chatbot.append((inputs, ""))
yield from update_ui(chatbot=chatbot, history=history, msg="等待响应") # 刷新界面
loading_msg = func_box.spinner_chatbot_loading(chatbot)
yield from update_ui(chatbot=loading_msg, history=history, msg="等待响应") # 刷新界面
try:
headers, payload = generate_payload(inputs, llm_kwargs, history, system_prompt, stream)
except RuntimeError as e:
chatbot[-1] = (inputs, f"您提供的api-key不满足要求不包含任何可用于{llm_kwargs['llm_model']}的api-key。您可能选择了错误的模型或请求源。")
yield from update_ui(chatbot=chatbot, history=history, msg="api-key不满足要求") # 刷新界面
return
history.append(inputs); history.append("")
retry = 0
while True:
try:
# make a POST request to the API endpoint, stream=True
from .bridge_all import model_info
from request_llm.bridge_all import model_info
endpoint = model_info[llm_kwargs['llm_model']]['endpoint']
response = requests.post(endpoint, headers=headers, proxies=proxies,
json=payload, stream=True, timeout=TIMEOUT_SECONDS);break
@ -163,7 +163,6 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
if retry > MAX_RETRY: raise TimeoutError
gpt_replying_buffer = ""
is_head_of_the_stream = True
if stream:
stream_response = response.iter_lines()
@ -181,24 +180,26 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
if is_head_of_the_stream and (r'"object":"error"' not in chunk.decode()):
# 数据流的第一帧不携带content
is_head_of_the_stream = False; continue
if chunk:
try:
chunk_decoded = chunk.decode()
# 前者API2D的
if ('data: [DONE]' in chunk_decoded) or (len(json.loads(chunk_decoded[6:])['choices'][0]["delta"]) == 0):
# 判定为数据流的结束gpt_replying_buffer也写完了
logging.info(f'[response] {gpt_replying_buffer}')
logging.info(f'[response]_{llm_kwargs["ipaddr"]} {gpt_replying_buffer}')
break
# 处理数据流的主体
chunkjson = json.loads(chunk_decoded[6:])
status_text = f"finish_reason: {chunkjson['choices'][0]['finish_reason']}"
# 如果这里抛出异常一般是文本过长详情见get_full_error的输出
gpt_replying_buffer = gpt_replying_buffer + json.loads(chunk_decoded[6:])['choices'][0]["delta"]["content"]
history[-1] = gpt_replying_buffer
chatbot[-1] = (history[-2], history[-1])
count_time = round(time.time() - llm_kwargs['start_time'], 3)
status_text = f"finish_reason: {chunkjson['choices'][0]['finish_reason']}\t" \
f"本次对话耗时: {func_box.html_tag_color(tag=f'{count_time}s')}"
yield from update_ui(chatbot=chatbot, history=history, msg=status_text) # 刷新界面
except Exception as e:
traceback.print_exc()
yield from update_ui(chatbot=chatbot, history=history, msg="Json解析不合常规") # 刷新界面
@ -207,7 +208,7 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
error_msg = chunk_decoded
if "reduce the length" in error_msg:
if len(history) >= 2: history[-1] = ""; history[-2] = "" # 清除当前溢出的输入history[-2] 是本次输入, history[-1] 是本次输出
history = clip_history(inputs=inputs, history=history, tokenizer=model_info[llm_kwargs['llm_model']]['tokenizer'],
history = clip_history(inputs=inputs, history=history, tokenizer=model_info[llm_kwargs['llm_model']]['tokenizer'],
max_token_limit=(model_info[llm_kwargs['llm_model']]['max_token'])) # history至少释放二分之一
chatbot[-1] = (chatbot[-1][0], "[Local Message] Reduce the length. 本次输入过长, 或历史数据过长. 历史缓存数据已部分释放, 您可以请再次尝试. (若再次失败则更可能是因为输入过长.)")
# history = [] # 清除历史
@ -227,6 +228,9 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp
chatbot[-1] = (chatbot[-1][0], f"[Local Message] 异常 \n\n{tb_str} \n\n{regular_txt_to_markdown(chunk_decoded)}")
yield from update_ui(chatbot=chatbot, history=history, msg="Json异常" + error_msg) # 刷新界面
return
count_tokens = func_box.num_tokens_from_string(listing=history)
status_text += f'\t 本次对话使用tokens: {func_box.html_tag_color(count_tokens)}'
yield from update_ui(chatbot=chatbot, history=history, msg=status_text) # 刷新界面
def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
"""
@ -234,13 +238,18 @@ def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
"""
if not is_any_api_key(llm_kwargs['api_key']):
raise AssertionError("你提供了错误的API_KEY。\n\n1. 临时解决方案直接在输入区键入api_key然后回车提交。\n\n2. 长效解决方案在config.py中配置。")
api_key = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model'])
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
if llm_kwargs['llm_model'].startswith('proxy-'):
api_key = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model'])
headers = {
"Content-Type": "application/json",
"api-key": f"{api_key}"
}
else:
api_key = select_api_key(llm_kwargs['api_key'], llm_kwargs['llm_model'])
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
conversation_cnt = len(history) // 2
@ -277,9 +286,20 @@ def generate_payload(inputs, llm_kwargs, history, system_prompt, stream):
"frequency_penalty": 0,
}
try:
print(f" {llm_kwargs['llm_model']} : {conversation_cnt} : {inputs[:100]} ..........")
print("\033[1;35m", f"{llm_kwargs['llm_model']}_{llm_kwargs['ipaddr']} :", "\033[0m", f"{conversation_cnt} : {inputs[:100]} ..........")
except:
print('输入中可能存在乱码。')
return headers,payload
return headers, payload
if __name__ == '__main__':
llm_kwargs = {
'api_key': 'sk-',
'llm_model': 'gpt-3.5-turbo',
'top_p': 1,
'max_length': 512,
'temperature': 1,
# 'ipaddr': ipaddr.client.host
}
chat = []
predict('你好', llm_kwargs=llm_kwargs, chatbot=chat, plugin_kwargs={})
print(chat)

View File

@ -15,4 +15,11 @@ pymupdf
openai
numpy
arxiv
rich
pymupdf
pyperclip
scikit-learn
psutil
distro
python-dotenv
rich
Levenshtein

235
theme.py
View File

@ -1,6 +1,6 @@
import gradio as gr
from toolbox import get_conf
CODE_HIGHLIGHT, ADD_WAIFU = get_conf('CODE_HIGHLIGHT', 'ADD_WAIFU')
CODE_HIGHLIGHT, ADD_WAIFU, ADD_CHUANHU = get_conf('CODE_HIGHLIGHT', 'ADD_WAIFU', 'ADD_CHUANHU')
# gradio可用颜色列表
# gr.themes.utils.colors.slate (石板色)
# gr.themes.utils.colors.gray (灰色)
@ -29,105 +29,185 @@ CODE_HIGHLIGHT, ADD_WAIFU = get_conf('CODE_HIGHLIGHT', 'ADD_WAIFU')
def adjust_theme():
try:
color_er = gr.themes.utils.colors.fuchsia
set_theme = gr.themes.Default(
primary_hue=gr.themes.utils.colors.orange,
neutral_hue=gr.themes.utils.colors.gray,
font=["sans-serif", "Microsoft YaHei", "ui-sans-serif", "system-ui",
"sans-serif", gr.themes.utils.fonts.GoogleFont("Source Sans Pro")],
font_mono=["ui-monospace", "Consolas", "monospace", gr.themes.utils.fonts.GoogleFont("IBM Plex Mono")])
set_theme.set(
# Colors
input_background_fill_dark="*neutral_800",
# Transition
button_transition="none",
# Shadows
button_shadow="*shadow_drop",
button_shadow_hover="*shadow_drop_lg",
button_shadow_active="*shadow_inset",
input_shadow="0 0 0 *shadow_spread transparent, *shadow_inset",
input_shadow_focus="0 0 0 *shadow_spread *secondary_50, *shadow_inset",
input_shadow_focus_dark="0 0 0 *shadow_spread *neutral_700, *shadow_inset",
checkbox_label_shadow="*shadow_drop",
block_shadow="*shadow_drop",
form_gap_width="1px",
# Button borders
input_border_width="1px",
input_background_fill="white",
# Gradients
stat_background_fill="linear-gradient(to right, *primary_400, *primary_200)",
stat_background_fill_dark="linear-gradient(to right, *primary_400, *primary_600)",
error_background_fill=f"linear-gradient(to right, {color_er.c100}, *background_fill_secondary)",
error_background_fill_dark="*background_fill_primary",
checkbox_label_background_fill="linear-gradient(to top, *neutral_50, white)",
checkbox_label_background_fill_dark="linear-gradient(to top, *neutral_900, *neutral_800)",
checkbox_label_background_fill_hover="linear-gradient(to top, *neutral_100, white)",
checkbox_label_background_fill_hover_dark="linear-gradient(to top, *neutral_900, *neutral_800)",
button_primary_background_fill="linear-gradient(to bottom right, *primary_100, *primary_300)",
button_primary_background_fill_dark="linear-gradient(to bottom right, *primary_500, *primary_600)",
button_primary_background_fill_hover="linear-gradient(to bottom right, *primary_100, *primary_200)",
button_primary_background_fill_hover_dark="linear-gradient(to bottom right, *primary_500, *primary_500)",
button_primary_border_color_dark="*primary_500",
button_secondary_background_fill="linear-gradient(to bottom right, *neutral_100, *neutral_200)",
button_secondary_background_fill_dark="linear-gradient(to bottom right, *neutral_600, *neutral_700)",
button_secondary_background_fill_hover="linear-gradient(to bottom right, *neutral_100, *neutral_100)",
button_secondary_background_fill_hover_dark="linear-gradient(to bottom right, *neutral_600, *neutral_600)",
button_cancel_background_fill=f"linear-gradient(to bottom right, {color_er.c100}, {color_er.c200})",
button_cancel_background_fill_dark=f"linear-gradient(to bottom right, {color_er.c600}, {color_er.c700})",
button_cancel_background_fill_hover=f"linear-gradient(to bottom right, {color_er.c100}, {color_er.c100})",
button_cancel_background_fill_hover_dark=f"linear-gradient(to bottom right, {color_er.c600}, {color_er.c600})",
button_cancel_border_color=color_er.c200,
button_cancel_border_color_dark=color_er.c600,
button_cancel_text_color=color_er.c600,
button_cancel_text_color_dark="white",
)
set_theme = gr.themes.Soft(
primary_hue=gr.themes.Color(
c50="#EBFAF2",
c100="#CFF3E1",
c200="#A8EAC8",
c300="#77DEA9",
c400="#3FD086",
c500="#02C160",
c600="#06AE56",
c700="#05974E",
c800="#057F45",
c900="#04673D",
c950="#2E5541",
name="small_and_beautiful",
),
secondary_hue=gr.themes.Color(
c50="#576b95",
c100="#576b95",
c200="#576b95",
c300="#576b95",
c400="#576b95",
c500="#576b95",
c600="#576b95",
c700="#576b95",
c800="#576b95",
c900="#576b95",
c950="#576b95",
),
neutral_hue=gr.themes.Color(
name="gray",
c50="#f6f7f8",
# c100="#f3f4f6",
c100="#F2F2F2",
c200="#e5e7eb",
c300="#d1d5db",
c400="#B2B2B2",
c500="#808080",
c600="#636363",
c700="#515151",
c800="#393939",
# c900="#272727",
c900="#2B2B2B",
c950="#171717",
),
radius_size=gr.themes.sizes.radius_sm,
).set(
button_primary_background_fill="*primary_500",
button_primary_background_fill_dark="*primary_600",
button_primary_background_fill_hover="*primary_400",
button_primary_border_color="*primary_500",
button_primary_border_color_dark="*primary_600",
button_primary_text_color="wihte",
button_primary_text_color_dark="white",
button_secondary_background_fill="*neutral_100",
button_secondary_background_fill_hover="*neutral_50",
button_secondary_background_fill_dark="*neutral_900",
button_secondary_text_color="*neutral_800",
button_secondary_text_color_dark="white",
background_fill_primary="#F7F7F7",
background_fill_primary_dark="#1F1F1F",
block_title_text_color="*primary_500",
block_title_background_fill_dark="*primary_900",
block_label_background_fill_dark="*primary_900",
input_background_fill="#F6F6F6",
chatbot_code_background_color="*neutral_950",
chatbot_code_background_color_dark="*neutral_950",
)
js = ''
if ADD_CHUANHU:
with open("./docs/assets/custom.js", "r", encoding="utf-8") as f, \
open("./docs/assets/external-scripts.js", "r", encoding="utf-8") as f1:
customJS = f.read()
externalScripts = f1.read()
js += f'<script>{customJS}</script><script async>{externalScripts}</script>'
# 添加一个萌萌的看板娘
if ADD_WAIFU:
js = """
js += """
<script src="file=docs/waifu_plugin/jquery.min.js"></script>
<script src="file=docs/waifu_plugin/jquery-ui.min.js"></script>
<script src="file=docs/waifu_plugin/autoload.js"></script>
"""
gradio_original_template_fn = gr.routes.templates.TemplateResponse
def gradio_new_template_fn(*args, **kwargs):
res = gradio_original_template_fn(*args, **kwargs)
res.body = res.body.replace(b'</html>', f'{js}</html>'.encode("utf8"))
res.init_headers()
return res
gr.routes.templates.TemplateResponse = gradio_new_template_fn # override gradio template
gradio_original_template_fn = gr.routes.templates.TemplateResponse
def gradio_new_template_fn(*args, **kwargs):
res = gradio_original_template_fn(*args, **kwargs)
res.body = res.body.replace(b'</html>', f'{js}</html>'.encode("utf8"))
res.init_headers()
return res
gr.routes.templates.TemplateResponse = gradio_new_template_fn # override gradio template
except:
set_theme = None
print('gradio版本较旧, 不能自定义字体和颜色')
return set_theme
with open("docs/assets/custom.css", "r", encoding="utf-8") as f:
customCSS = f.read()
custom_css = customCSS
advanced_css = """
.markdown-body table {
#debug_mes {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
z-index: 1; /* 设置更高的 z-index 值 */
margin-bottom: 10px !important;
}
#chat_txt {
display: flex;
flex-direction: column-reverse;
overflow-y: auto !important;
z-index: 3;
flex-grow: 1; /* 自动填充剩余空间 */
position: absolute;
bottom: 0;
left: 0;
width: 100%;
margin-bottom: 35px !important;
}
#sm_btn {
display: flex;
flex-wrap: unset !important;
gap: 5px !important;
width: var(--size-full);
}
textarea {
resize: none;
height: 100%; /* 填充父元素的高度 */
}
#main_chatbot {
height: 75vh !important;
max-height: 75vh !important;
/* overflow: auto !important; */
z-index: 2;
}
#prompt_result{
height: 60vh !important;
max-height: 60vh !important;
}
.wrap.svelte-18telvq.svelte-18telvq {
padding: var(--block-padding) !important;
height: 100% !important;
max-height: 95% !important;
overflow-y: auto !important;
}
.app.svelte-1mya07g.svelte-1mya07g {
max-width: 100%;
position: relative;
/* margin: auto; */
padding: var(--size-4);
width: 100%;
height: 100%;
}
.md-message table {
margin: 1em 0;
border-collapse: collapse;
empty-cells: show;
}
.markdown-body th, .markdown-body td {
.md-message th, .md-message td {
border: 1.2px solid var(--border-color-primary);
padding: 5px;
}
.markdown-body thead {
.md-message thead {
background-color: rgba(175,184,193,0.2);
}
.markdown-body thead th {
.md-message thead th {
padding: .5em .2em;
}
.markdown-body ol, .markdown-body ul {
.md-message ol, .md-message ul {
padding-inline-start: 2em !important;
}
/* chat box. */
[class *= "message"] {
gap: 7px !important;
border-radius: var(--radius-xl) !important;
/* padding: var(--spacing-xl) !important; */
/* font-size: var(--text-md) !important; */
@ -137,27 +217,40 @@ advanced_css = """
}
[data-testid = "bot"] {
max-width: 95%;
letter-spacing: 0.5px;
font-weight: normal;
/* width: auto !important; */
border-bottom-left-radius: 0 !important;
}
.dark [data-testid = "bot"] {
max-width: 95%;
color: #ccd2db !important;
letter-spacing: 0.5px;
font-weight: normal;
/* width: auto !important; */
border-bottom-left-radius: 0 !important;
}
[data-testid = "user"] {
max-width: 100%;
letter-spacing: 0.5px;
/* width: auto !important; */
border-bottom-right-radius: 0 !important;
}
/* linein code block. */
.markdown-body code {
.md-message code {
display: inline;
white-space: break-spaces;
border-radius: 6px;
margin: 0 2px 0 2px;
padding: .2em .4em .1em .4em;
background-color: rgba(13, 17, 23, 0.95);
color: #c9d1d9;
color: #eff0f2;
}
.dark .markdown-body code {
.dark .md-message code {
display: inline;
white-space: break-spaces;
border-radius: 6px;
@ -167,7 +260,7 @@ advanced_css = """
}
/* code block css */
.markdown-body pre code {
.md-message pre code {
display: block;
overflow: auto;
white-space: pre;
@ -177,7 +270,7 @@ advanced_css = """
margin: 1em 2em 1em 0.5em;
}
.dark .markdown-body pre code {
.dark .md-message pre code {
display: block;
overflow: auto;
white-space: pre;

View File

@ -1,11 +1,18 @@
import html
import markdown
import importlib
import time
import inspect
import re
import os
import gradio as gr
import func_box
from latex2mathml.converter import convert as tex2mathml
from functools import wraps, lru_cache
import shutil
import os
import time
import glob
import sys
import threading
############################### 插件输入输出接驳区 #######################################
pj = os.path.join
"""
@ -40,36 +47,62 @@ def ArgsGeneralWrapper(f):
"""
装饰器函数,用于重组输入参数,改变输入参数的顺序与结构。
"""
def decorated(cookies, max_length, llm_model, txt, txt2, top_p, temperature, chatbot, history, system_prompt, plugin_advanced_arg, *args):
txt_passon = txt
if txt == "" and txt2 != "": txt_passon = txt2
def decorated(cookies, max_length, llm_model, txt, top_p, temperature,
chatbot, history, system_prompt, models, plugin_advanced_arg, ipaddr: gr.Request, *args):
""""""
# 引入一个有cookie的chatbot
start_time = time.time()
encrypt, private = get_conf('switch_model')[0]['key']
private_key, = get_conf('private_key')
cookies.update({
'top_p':top_p,
'temperature':temperature,
})
llm_kwargs = {
'api_key': cookies['api_key'],
'llm_model': llm_model,
'top_p':top_p,
'max_length': max_length,
'temperature':temperature,
'temperature': temperature,
'ipaddr': ipaddr.client.host,
'start_time': start_time
}
plugin_kwargs = {
"advanced_arg": plugin_advanced_arg,
"parameters_def": ''
}
if len(args) > 1:
plugin_kwargs.update({'parameters_def': args[1]})
transparent_address_private = f'<p style="display:none;">\n{private_key}\n{ipaddr.client.host}\n</p>'
transparent_address = f'<p style="display:none;">\n{ipaddr.client.host}\n</p>'
if private in models:
if chatbot == []:
chatbot.append([None, f'隐私模式, 你的对话记录无法被他人检索 {transparent_address_private}'])
else:
chatbot[0] = [None, f'隐私模式, 你的对话记录无法被他人检索 {transparent_address_private}']
else:
if chatbot == []:
chatbot.append([None, f'正常对话模式, 你接来下的对话将会被记录并且可以被所有人检索你可以到Settings中选择隐私模式 {transparent_address}'])
else:
chatbot[0] = [None, f'正常对话模式, 你接来下的对话将会被记录并且可以被所有人检索你可以到Settings中选择隐私模式 {transparent_address}']
chatbot_with_cookie = ChatBotWithCookies(cookies)
chatbot_with_cookie.write_list(chatbot)
txt_passon = txt
if encrypt in models: txt_passon = func_box.encryption_str(txt)
yield from f(txt_passon, llm_kwargs, plugin_kwargs, chatbot_with_cookie, history, system_prompt, *args)
return decorated
def update_ui(chatbot, history, msg='正常', **kwargs): # 刷新界面
def update_ui(chatbot, history, msg='正常', *args): # 刷新界面
"""
刷新用户界面
"""
assert isinstance(chatbot, ChatBotWithCookies), "在传递chatbot的过程中不要将其丢弃。必要时可用clear将其清空然后用for+append循环重新赋值。"
yield chatbot.get_cookies(), chatbot, history, msg
threading.Thread(target=func_box.thread_write_chat, args=(chatbot, history)).start()
# func_box.thread_write_chat(chatbot, history)
def update_ui_lastest_msg(lastmsg, chatbot, history, delay=1): # 刷新界面
"""
@ -126,9 +159,14 @@ def HotReload(f):
def decorated(*args, **kwargs):
fn_name = f.__name__
f_hot_reload = getattr(importlib.reload(inspect.getmodule(f)), fn_name)
yield from f_hot_reload(*args, **kwargs)
try:
yield from f_hot_reload(*args, **kwargs)
except TypeError:
args = tuple(args[element] for element in range(len(args)) if element != 6)
yield from f_hot_reload(*args, **kwargs)
return decorated
####################################### 其他小工具 #####################################
"""
========================================================================
@ -192,8 +230,7 @@ def write_results_to_file(history, file_name=None):
# remove everything that cannot be handled by utf8
f.write(content.encode('utf-8', 'ignore').decode())
f.write('\n\n')
res = '以上材料已经被写入' + os.path.abspath(f'./gpt_log/{file_name}')
print(res)
res = '以上材料已经被写入' + f'./gpt_log/{file_name}'
return res
@ -218,37 +255,51 @@ def report_execption(chatbot, history, a, b):
history.append(b)
def text_divide_paragraph(text):
"""
将文本按照段落分隔符分割开生成带有段落标签的HTML代码。
"""
pre = '<div class="markdown-body">'
suf = '</div>'
if text.startswith(pre) and text.endswith(suf):
return text
if '```' in text:
# careful input
return pre + text + suf
else:
# wtf input
lines = text.split("\n")
for i, line in enumerate(lines):
lines[i] = lines[i].replace(" ", "&nbsp;")
text = "</br>".join(lines)
return pre + text + suf
import re
def text_divide_paragraph(input_str):
if input_str:
code_blocks = re.findall(r'```[\s\S]*?```', input_str)
@lru_cache(maxsize=128) # 使用 lru缓存 加快转换速度
for i, block in enumerate(code_blocks):
input_str = input_str.replace(block, f'{{{{CODE_BLOCK_{i}}}}}')
if code_blocks:
sections = re.split(r'({{{{\w+}}}})', input_str)
for idx, section in enumerate(sections):
if 'CODE_BLOCK' in section or section.startswith(' '):
continue
sections[idx] = re.sub(r'(?!```)(?<!\n)\n(?!(\n|^)( {0,3}[\*\+\-]|[0-9]+\.))', '\n\n', section)
input_str = ''.join(sections)
for i, block in enumerate(code_blocks):
input_str = input_str.replace(f'{{{{CODE_BLOCK_{i}}}}}', block.replace('\n', '\n'))
else:
lines = input_str.split('\n')
for idx, line in enumerate(lines[:-1]):
if not line.strip():
continue
if not (lines[idx + 1].startswith(' ') or lines[idx + 1].startswith('\t')):
lines[idx] += '\n' # 将一个换行符替换为两个换行符
input_str = '\n'.join(lines)
return input_str
@lru_cache(maxsize=128) # 使用 lru缓存 加快转换速度
def markdown_convertion(txt):
"""
将Markdown格式的文本转换为HTML格式。如果包含数学公式则先将公式转换为HTML格式。
"""
pre = '<div class="markdown-body">'
pre = '<div class="md-message">'
suf = '</div>'
raw_pre = '<div class="raw-message hideM">'
raw_suf = '</div>'
if txt.startswith(pre) and txt.endswith(suf):
# print('警告,输入了已经经过转化的字符串,二次转化可能出问题')
return txt # 已经被转化过,不需要再次转化
return txt # 已经被转化过,不需要再次转化
if txt.startswith(raw_pre) and txt.endswith(raw_suf):
return txt # 已经被转化过,不需要再次转化
raw_hide = raw_pre + txt + raw_suf
markdown_extension_configs = {
'mdx_math': {
'enable_dollar_delimiter': True,
@ -257,13 +308,6 @@ def markdown_convertion(txt):
}
find_equation_pattern = r'<script type="math/tex(?:.*?)>(.*?)</script>'
def tex2mathml_catch_exception(content, *args, **kwargs):
try:
content = tex2mathml(content, *args, **kwargs)
except:
content = content
return content
def replace_math_no_render(match):
content = match.group(1)
if 'mode=display' in match.group(0):
@ -279,40 +323,47 @@ def markdown_convertion(txt):
content = content.replace('\\begin{aligned}', '\\begin{array}')
content = content.replace('\\end{aligned}', '\\end{array}')
content = content.replace('&', ' ')
content = tex2mathml_catch_exception(content, display="block")
content = tex2mathml(content, display="block")
return content
else:
return tex2mathml_catch_exception(content)
return tex2mathml(content)
def markdown_bug_hunt(content):
"""
解决一个mdx_math的bug单$包裹begin命令时多余<script>
"""
content = content.replace('<script type="math/tex">\n<script type="math/tex; mode=display">', '<script type="math/tex; mode=display">')
content = content.replace('<script type="math/tex">\n<script type="math/tex; mode=display">',
'<script type="math/tex; mode=display">')
content = content.replace('</script>\n</script>', '</script>')
return content
def no_code(txt):
if '```' not in txt:
if '```' not in txt:
return True
else:
if '```reference' in txt: return True # newbing
else: return False
if '```reference' in txt:
return True # newbing
else:
return False
if ('$' in txt) and no_code(txt): # 有$标识的公式符号,且没有代码段```的标识
if ('$$' in txt) and no_code(txt): # 有$标识的公式符号,且没有代码段```的标识
# convert everything to html format
split = markdown.markdown(text='---')
txt = re.sub(r'\$\$((?:.|\n)*?)\$\$', lambda match: '$$' + re.sub(r'\n+', '</br>', match.group(1)) + '$$', txt)
convert_stage_1 = markdown.markdown(text=txt, extensions=['mdx_math', 'fenced_code', 'tables', 'sane_lists'], extension_configs=markdown_extension_configs)
convert_stage_1 = markdown_bug_hunt(convert_stage_1)
# re.DOTALL: Make the '.' special character match any character at all, including a newline; without this flag, '.' will match anything except a newline. Corresponds to the inline flag (?s).
# 1. convert to easy-to-copy tex (do not render math)
convert_stage_2_1, n = re.subn(find_equation_pattern, replace_math_no_render, convert_stage_1, flags=re.DOTALL)
# 2. convert to rendered equation
convert_stage_2_2, n = re.subn(find_equation_pattern, replace_math_render, convert_stage_1, flags=re.DOTALL)
convert_stage_1_resp = convert_stage_1.replace('</br>', '')
convert_stage_2_2, n = re.subn(find_equation_pattern, replace_math_render, convert_stage_1_resp, flags=re.DOTALL)
# cat them together
return pre + convert_stage_2_1 + f'{split}' + convert_stage_2_2 + suf
context = pre + convert_stage_2_1 + f'{split}' + convert_stage_2_2 + suf
return raw_hide + context # 破坏html 结构,并显示源码
else:
return pre + markdown.markdown(txt, extensions=['fenced_code', 'codehilite', 'tables', 'sane_lists']) + suf
context = pre + markdown.markdown(txt, extensions=['fenced_code', 'codehilite', 'tables', 'sane_lists']) + suf
return raw_hide + context # 破坏html 结构,并显示源码
def close_up_code_segment_during_stream(gpt_reply):
@ -326,9 +377,9 @@ def close_up_code_segment_during_stream(gpt_reply):
str: 返回一个新的字符串,将输出代码片段的“后面的```”补上。
"""
if '```' not in gpt_reply:
if '```' not in str(gpt_reply):
return gpt_reply
if gpt_reply.endswith('```'):
if str(gpt_reply).endswith('```'):
return gpt_reply
# 排除了以上两个情况,我们
@ -354,7 +405,8 @@ def format_io(self, y):
if gpt_reply is not None: gpt_reply = close_up_code_segment_during_stream(gpt_reply)
# process
y[-1] = (
None if i_ask is None else markdown.markdown(i_ask, extensions=['fenced_code', 'tables']),
# None if i_ask is None else markdown.markdown(i_ask, extensions=['fenced_code', 'tables']),
None if i_ask is None else markdown_convertion(i_ask),
None if gpt_reply is None else markdown_convertion(gpt_reply)
)
return y
@ -452,42 +504,51 @@ def promote_file_to_downloadzone(file, rename_file=None, chatbot=None):
else: current = []
chatbot._cookies.update({'file_to_promote': [new_path] + current})
def on_file_uploaded(files, chatbot, txt, txt2, checkboxes):
def get_user_upload(chatbot, ipaddr: gr.Request):
"""
获取用户上传过的文件
"""
private_upload = './private_upload'
user_history = os.path.join(private_upload, ipaddr.client.host)
history = """| 编号 | 目录 | 目录内文件 |\n| --- | --- | --- |\n"""
count_num = 1
for root, d, file in os.walk(user_history):
file_link = "<br>".join([f'{func_box.html_view_blank(f"{root}/{i}")}' for i in file])
history += f'| {count_num} | {root} | {file_link} |\n'
count_num += 1
chatbot.append(['Load Submission History....',
f'[Local Message] 请自行复制以下目录 or 目录+文件, 填入输入框以供函数区高亮按钮使用\n\n'
f'{func_box.html_tag_color("提交前记得请检查头尾空格哦~")}\n\n'
f'{history}'
])
return chatbot
def on_file_uploaded(files, chatbot, txt, ipaddr: gr.Request):
"""
当文件被上传时的回调函数
"""
if len(files) == 0:
return chatbot, txt
import shutil
import os
import time
import glob
from toolbox import extract_archive
try:
shutil.rmtree('./private_upload/')
except:
pass
time_tag = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
os.makedirs(f'private_upload/{time_tag}', exist_ok=True)
private_upload = './private_upload'
# shutil.rmtree('./private_upload/') 不需要删除文件
time_tag_path = os.path.join(private_upload, ipaddr.client.host, time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()))
os.makedirs(f'{time_tag_path}', exist_ok=True)
err_msg = ''
for file in files:
file_origin_name = os.path.basename(file.orig_name)
shutil.copy(file.name, f'private_upload/{time_tag}/{file_origin_name}')
err_msg += extract_archive(f'private_upload/{time_tag}/{file_origin_name}',
dest_dir=f'private_upload/{time_tag}/{file_origin_name}.extract')
moved_files = [fp for fp in glob.glob('private_upload/**/*', recursive=True)]
if "底部输入区" in checkboxes:
txt = ""
txt2 = f'private_upload/{time_tag}'
else:
txt = f'private_upload/{time_tag}'
txt2 = ""
shutil.copy(file.name, f'{time_tag_path}/{file_origin_name}')
err_msg += extract_archive(f'{time_tag_path}/{file_origin_name}',
dest_dir=f'{time_tag_path}/{file_origin_name}.extract')
moved_files = [fp for fp in glob.glob(f'{time_tag_path}/**/*', recursive=True)]
txt = f'{time_tag_path}'
moved_files_str = '\t\n\n'.join(moved_files)
chatbot.append(['我上传了文件,请查收',
chatbot.append([None,
f'[Local Message] 收到以下文件: \n\n{moved_files_str}' +
f'\n\n调用路径参数已自动修正到: \n\n{txt}' +
f'\n\n现在您点击任意“红颜色”标识的函数插件时,以上文件将被作为输入参数'+err_msg])
return chatbot, txt, txt2
f'\n\n现在您点击任意“高亮”标识的函数插件时,以上文件将被作为输入参数'+err_msg])
return chatbot, txt
def on_report_generated(cookies, files, chatbot):
@ -516,6 +577,13 @@ def is_api2d_key(key):
else:
return False
def is_proxy_key(key):
if key.startswith('proxy-') and len(key) == 38:
return True
else:
return False
def is_any_api_key(key):
if ',' in key:
keys = key.split(',')
@ -523,7 +591,7 @@ def is_any_api_key(key):
if is_any_api_key(k): return True
return False
else:
return is_openai_api_key(key) or is_api2d_key(key)
return is_openai_api_key(key) or is_api2d_key(key) or is_proxy_key(key)
def what_keys(keys):
avail_key_list = {'OpenAI Key':0, "API2D Key":0}
@ -537,7 +605,14 @@ def what_keys(keys):
if is_api2d_key(k):
avail_key_list['API2D Key'] += 1
return f"检测到: OpenAI Key {avail_key_list['OpenAI Key']}API2D Key {avail_key_list['API2D Key']}"
for k in key_list:
if is_proxy_key(k):
avail_key_list['Proxy Key'] += 1
return f"检测到: \n" \
f"OpenAI Key {avail_key_list['OpenAI Key']}\n" \
f"API2D Key {avail_key_list['API2D Key']}\n" \
f"Proxy Key {avail_key_list['API2D Key']}\n"
def select_api_key(keys, llm_model):
import random
@ -552,6 +627,10 @@ def select_api_key(keys, llm_model):
for k in key_list:
if is_api2d_key(k): avail_key_list.append(k)
if llm_model.startswith('proxy-'):
for k in key_list:
if is_proxy_key(k): avail_key_list.append(k.replace('proxy-', ''))
if len(avail_key_list) == 0:
raise RuntimeError(f"您提供的api-key不满足要求不包含任何可用于{llm_model}的api-key。您可能选择了错误的模型或请求源。")
@ -622,6 +701,12 @@ def read_single_conf_with_lru_cache(arg):
except:
try:
# 优先级2. 获取config_private中的配置
# 获取当前文件所在目录的路径
current_dir = os.path.dirname(os.path.abspath(__file__))
# 获取上一层目录的路径
parent_dir = os.path.dirname(current_dir)
# 将上一层目录添加到Python的搜索路径中
sys.path.append(parent_dir)
r = getattr(importlib.import_module('config_private'), arg)
except:
# 优先级3. 获取config中的配置
@ -676,6 +761,7 @@ class DummyWith():
def __exit__(self, exc_type, exc_value, traceback):
return
def run_gradio_in_subpath(demo, auth, port, custom_path):
"""
把gradio的运行地址更改到指定的二次路径上
@ -842,4 +928,3 @@ def objload(file='objdump.tmp'):
return
with open(file, 'rb') as f:
return pickle.load(f)