Spaces:
Running
Running
JohnSmith9982/ChuanhuChatGPT
#1
by
Dorado607
- opened
- .gitattributes +34 -0
- .gitignore +0 -146
- CITATION.cff +5 -5
- ChuanhuChatbot.py +23 -49
- Dockerfile +8 -11
- README.md +2 -1
- README_origin.md +0 -142
- assets/Kelpy-Codos.js +76 -0
- assets/custom.css +21 -212
- assets/custom.js +54 -259
- assets/favicon.ico +0 -0
- assets/favicon.png +0 -0
- assets/html/appearance_switcher.html +10 -5
- assets/html/billing_info.html +0 -9
- assets/html/update.html +0 -25
- chatgpt - macOS.command +7 -0
- chatgpt - windows.bat +14 -0
- config.json +3 -0
- config_example.json +14 -48
- custom.css +162 -0
- history/2023-06-14_15-05-04.json +0 -0
- locale/en_US.json +7 -18
- locale/ja_JP.json +6 -17
- locale/ko_KR.json +0 -86
- locale/sv-SE.json +0 -84
- modules/base_model.py +561 -0
- modules/config.py +27 -106
- modules/index_func.py +5 -13
- modules/llama_func.py +166 -0
- modules/models.py +625 -0
- modules/models/Google_PaLM.py +0 -26
- modules/models/azure.py +0 -17
- modules/models/base_model.py +26 -124
- modules/models/models.py +15 -27
- modules/overwrites.py +2 -1
- modules/presets.py +2 -7
- modules/utils.py +7 -46
- readme/README_en.md +9 -22
- readme/README_ja.md +9 -22
- requirements.txt +3 -5
- requirements_advanced.txt +0 -11
- run_Windows.bat +2 -21
.gitattributes
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
28 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
29 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
30 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
31 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
32 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
33 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
34 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
.gitignore
DELETED
@@ -1,146 +0,0 @@
|
|
1 |
-
# Byte-compiled / optimized / DLL files
|
2 |
-
__pycache__/
|
3 |
-
*.py[cod]
|
4 |
-
*$py.class
|
5 |
-
|
6 |
-
# C extensions
|
7 |
-
*.so
|
8 |
-
|
9 |
-
# Distribution / packaging
|
10 |
-
.Python
|
11 |
-
build/
|
12 |
-
develop-eggs/
|
13 |
-
dist/
|
14 |
-
downloads/
|
15 |
-
eggs/
|
16 |
-
.eggs/
|
17 |
-
lib/
|
18 |
-
lib64/
|
19 |
-
parts/
|
20 |
-
sdist/
|
21 |
-
var/
|
22 |
-
wheels/
|
23 |
-
pip-wheel-metadata/
|
24 |
-
share/python-wheels/
|
25 |
-
*.egg-info/
|
26 |
-
.installed.cfg
|
27 |
-
*.egg
|
28 |
-
MANIFEST
|
29 |
-
history/
|
30 |
-
index/
|
31 |
-
|
32 |
-
# PyInstaller
|
33 |
-
# Usually these files are written by a python script from a template
|
34 |
-
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
35 |
-
*.manifest
|
36 |
-
*.spec
|
37 |
-
|
38 |
-
# Installer logs
|
39 |
-
pip-log.txt
|
40 |
-
pip-delete-this-directory.txt
|
41 |
-
|
42 |
-
# Unit test / coverage reports
|
43 |
-
htmlcov/
|
44 |
-
.tox/
|
45 |
-
.nox/
|
46 |
-
.coverage
|
47 |
-
.coverage.*
|
48 |
-
.cache
|
49 |
-
nosetests.xml
|
50 |
-
coverage.xml
|
51 |
-
*.cover
|
52 |
-
*.py,cover
|
53 |
-
.hypothesis/
|
54 |
-
.pytest_cache/
|
55 |
-
|
56 |
-
# Translations
|
57 |
-
*.mo
|
58 |
-
*.pot
|
59 |
-
|
60 |
-
# Django stuff:
|
61 |
-
*.log
|
62 |
-
local_settings.py
|
63 |
-
db.sqlite3
|
64 |
-
db.sqlite3-journal
|
65 |
-
|
66 |
-
# Flask stuff:
|
67 |
-
instance/
|
68 |
-
.webassets-cache
|
69 |
-
|
70 |
-
# Scrapy stuff:
|
71 |
-
.scrapy
|
72 |
-
|
73 |
-
# Sphinx documentation
|
74 |
-
docs/_build/
|
75 |
-
|
76 |
-
# PyBuilder
|
77 |
-
target/
|
78 |
-
|
79 |
-
# Jupyter Notebook
|
80 |
-
.ipynb_checkpoints
|
81 |
-
|
82 |
-
# IPython
|
83 |
-
profile_default/
|
84 |
-
ipython_config.py
|
85 |
-
|
86 |
-
# pyenv
|
87 |
-
.python-version
|
88 |
-
|
89 |
-
# pipenv
|
90 |
-
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
91 |
-
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
92 |
-
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
93 |
-
# install all needed dependencies.
|
94 |
-
#Pipfile.lock
|
95 |
-
|
96 |
-
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
97 |
-
__pypackages__/
|
98 |
-
|
99 |
-
# Celery stuff
|
100 |
-
celerybeat-schedule
|
101 |
-
celerybeat.pid
|
102 |
-
|
103 |
-
# SageMath parsed files
|
104 |
-
*.sage.py
|
105 |
-
|
106 |
-
# Environments
|
107 |
-
.env
|
108 |
-
.venv
|
109 |
-
env/
|
110 |
-
venv/
|
111 |
-
ENV/
|
112 |
-
env.bak/
|
113 |
-
venv.bak/
|
114 |
-
|
115 |
-
# Spyder project settings
|
116 |
-
.spyderproject
|
117 |
-
.spyproject
|
118 |
-
|
119 |
-
# Rope project settings
|
120 |
-
.ropeproject
|
121 |
-
|
122 |
-
# mkdocs documentation
|
123 |
-
/site
|
124 |
-
|
125 |
-
# mypy
|
126 |
-
.mypy_cache/
|
127 |
-
.dmypy.json
|
128 |
-
dmypy.json
|
129 |
-
|
130 |
-
# Pyre type checker
|
131 |
-
.pyre/
|
132 |
-
|
133 |
-
# Mac system file
|
134 |
-
**/.DS_Store
|
135 |
-
|
136 |
-
#vscode
|
137 |
-
.vscode
|
138 |
-
|
139 |
-
# 配置文件/模型文件
|
140 |
-
api_key.txt
|
141 |
-
config.json
|
142 |
-
auth.json
|
143 |
-
.models/
|
144 |
-
lora/
|
145 |
-
.idea
|
146 |
-
templates/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CITATION.cff
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
cff-version: 1.2.0
|
2 |
-
title:
|
3 |
message: >-
|
4 |
If you use this software, please cite it using these
|
5 |
metadata.
|
@@ -13,8 +13,8 @@ authors:
|
|
13 |
orcid: https://orcid.org/0009-0005-0357-272X
|
14 |
repository-code: 'https://github.com/GaiZhenbiao/ChuanhuChatGPT'
|
15 |
url: 'https://github.com/GaiZhenbiao/ChuanhuChatGPT'
|
16 |
-
abstract:
|
17 |
license: GPL-3.0
|
18 |
-
commit:
|
19 |
-
version: '
|
20 |
-
date-released: '2023-
|
|
|
1 |
cff-version: 1.2.0
|
2 |
+
title: ChuanhuChatGPT
|
3 |
message: >-
|
4 |
If you use this software, please cite it using these
|
5 |
metadata.
|
|
|
13 |
orcid: https://orcid.org/0009-0005-0357-272X
|
14 |
repository-code: 'https://github.com/GaiZhenbiao/ChuanhuChatGPT'
|
15 |
url: 'https://github.com/GaiZhenbiao/ChuanhuChatGPT'
|
16 |
+
abstract: Provided a light and easy to use interface for ChatGPT API
|
17 |
license: GPL-3.0
|
18 |
+
commit: bd0034c37e5af6a90bd9c2f7dd073f6cd27c61af
|
19 |
+
version: '20230405'
|
20 |
+
date-released: '2023-04-05'
|
ChuanhuChatbot.py
CHANGED
@@ -38,26 +38,17 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
38 |
status_display = gr.Markdown(get_geoip(), elem_id="status_display")
|
39 |
with gr.Row(elem_id="float_display"):
|
40 |
user_info = gr.Markdown(value="getting user info...", elem_id="user_info")
|
41 |
-
|
42 |
-
|
43 |
-
version_time=version_time(),
|
44 |
-
cancel_btn=i18n("取消"),
|
45 |
-
update_btn=i18n("更新"),
|
46 |
-
seenew_btn=i18n("详情"),
|
47 |
-
ok_btn=i18n("好"),
|
48 |
-
), visible=check_update)
|
49 |
-
|
50 |
-
with gr.Row(equal_height=True):
|
51 |
with gr.Column(scale=5):
|
52 |
with gr.Row():
|
53 |
-
chatbot = gr.Chatbot(label="Chuanhu Chat", elem_id="chuanhu_chatbot"
|
54 |
with gr.Row():
|
55 |
with gr.Column(min_width=225, scale=12):
|
56 |
user_input = gr.Textbox(
|
57 |
elem_id="user_input_tb",
|
58 |
-
show_label=False, placeholder=i18n("在这里输入")
|
59 |
-
|
60 |
-
)
|
61 |
with gr.Column(min_width=42, scale=1):
|
62 |
submitBtn = gr.Button(value="", variant="primary", elem_id="submit_btn")
|
63 |
cancelBtn = gr.Button(value="", variant="secondary", visible=False, elem_id="cancel_btn")
|
@@ -86,9 +77,9 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
86 |
label="API-Key",
|
87 |
)
|
88 |
if multi_api_key:
|
89 |
-
usageTxt = gr.Markdown(i18n("多账号模式已开启,无需输入key,可直接开始对话"), elem_id="usage_display", elem_classes="insert_block"
|
90 |
else:
|
91 |
-
usageTxt = gr.Markdown(i18n("**发送消息** 或 **提交key** 以显示额度"), elem_id="usage_display", elem_classes="insert_block"
|
92 |
model_select_dropdown = gr.Dropdown(
|
93 |
label=i18n("选择模型"), choices=MODELS, multiselect=False, value=MODELS[DEFAULT_MODEL], interactive=True
|
94 |
)
|
@@ -96,8 +87,8 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
96 |
label=i18n("选择LoRA模型"), choices=[], multiselect=False, interactive=True, visible=False
|
97 |
)
|
98 |
with gr.Row():
|
99 |
-
single_turn_checkbox = gr.Checkbox(label=i18n("单轮对话"), value=False
|
100 |
-
use_websearch_checkbox = gr.Checkbox(label=i18n("使用在线搜索"), value=False
|
101 |
language_select_dropdown = gr.Dropdown(
|
102 |
label=i18n("选择回复语言(针对搜索&索引功能)"),
|
103 |
choices=REPLY_LANGUAGES,
|
@@ -116,8 +107,8 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
116 |
placeholder=i18n("在这里输入System Prompt..."),
|
117 |
label="System prompt",
|
118 |
value=INITIAL_SYSTEM_PROMPT,
|
119 |
-
lines=10
|
120 |
-
)
|
121 |
with gr.Accordion(label=i18n("加载Prompt模板"), open=True):
|
122 |
with gr.Column():
|
123 |
with gr.Row():
|
@@ -127,8 +118,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
127 |
choices=get_template_names(plain=True),
|
128 |
multiselect=False,
|
129 |
value=get_template_names(plain=True)[0],
|
130 |
-
|
131 |
-
)
|
132 |
with gr.Column(scale=1):
|
133 |
templateRefreshBtn = gr.Button(i18n("🔄 刷新"))
|
134 |
with gr.Row():
|
@@ -139,8 +129,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
139 |
get_template_names(plain=True)[0], mode=1
|
140 |
),
|
141 |
multiselect=False,
|
142 |
-
|
143 |
-
)
|
144 |
|
145 |
with gr.Tab(label=i18n("保存/加载")):
|
146 |
with gr.Accordion(label=i18n("保存/加载对话历史记录"), open=True):
|
@@ -150,14 +139,10 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
150 |
historyFileSelectDropdown = gr.Dropdown(
|
151 |
label=i18n("从列表中加载对话"),
|
152 |
choices=get_history_names(plain=True),
|
153 |
-
multiselect=False
|
154 |
-
container=False,
|
155 |
)
|
156 |
-
with gr.
|
157 |
-
|
158 |
-
historyRefreshBtn = gr.Button(i18n("🔄 刷新"))
|
159 |
-
with gr.Column(min_width=42, scale=1):
|
160 |
-
historyDeleteBtn = gr.Button(i18n("🗑️ 删除"))
|
161 |
with gr.Row():
|
162 |
with gr.Column(scale=6):
|
163 |
saveFileName = gr.Textbox(
|
@@ -165,8 +150,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
165 |
placeholder=i18n("设置文件名: 默认为.json,可选为.md"),
|
166 |
label=i18n("设置保存文件名"),
|
167 |
value=i18n("对话历史记录"),
|
168 |
-
|
169 |
-
)
|
170 |
with gr.Column(scale=1):
|
171 |
saveHistoryBtn = gr.Button(i18n("💾 保存对话"))
|
172 |
exportMarkdownBtn = gr.Button(i18n("📝 导出为Markdown"))
|
@@ -176,12 +160,11 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
176 |
downloadFile = gr.File(interactive=True)
|
177 |
|
178 |
with gr.Tab(label=i18n("高级")):
|
|
|
179 |
gr.HTML(get_html("appearance_switcher.html").format(label=i18n("切换亮暗色主题")), elem_classes="insert_block")
|
180 |
use_streaming_checkbox = gr.Checkbox(
|
181 |
-
label=i18n("实时传输回答"), value=True, visible=ENABLE_STREAMING_OPTION
|
182 |
)
|
183 |
-
checkUpdateBtn = gr.Button(i18n("🔄 检查更新..."), visible=check_update)
|
184 |
-
gr.Markdown(i18n("# ⚠️ 务必谨慎更改 ⚠️"), elem_id="advanced_warning")
|
185 |
with gr.Accordion(i18n("参数"), open=False):
|
186 |
temperature_slider = gr.Slider(
|
187 |
minimum=-0,
|
@@ -209,7 +192,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
209 |
)
|
210 |
stop_sequence_txt = gr.Textbox(
|
211 |
show_label=True,
|
212 |
-
placeholder=i18n("
|
213 |
label="stop",
|
214 |
value="",
|
215 |
lines=1,
|
@@ -261,7 +244,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
261 |
lines=1,
|
262 |
)
|
263 |
|
264 |
-
with gr.Accordion(i18n("网络设置"), open=False):
|
265 |
# 优先展示自定义的api_host
|
266 |
apihostTxt = gr.Textbox(
|
267 |
show_label=True,
|
@@ -269,7 +252,6 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
269 |
label="API-Host",
|
270 |
value=config.api_host or shared.API_HOST,
|
271 |
lines=1,
|
272 |
-
container=False,
|
273 |
)
|
274 |
changeAPIURLBtn = gr.Button(i18n("🔄 切换API地址"))
|
275 |
proxyTxt = gr.Textbox(
|
@@ -278,7 +260,6 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
278 |
label=i18n("代理地址(示例:http://127.0.0.1:10809)"),
|
279 |
value="",
|
280 |
lines=2,
|
281 |
-
container=False,
|
282 |
)
|
283 |
changeProxyBtn = gr.Button(i18n("🔄 设置代理地址"))
|
284 |
default_btn = gr.Button(i18n("🔙 恢复默认设置"))
|
@@ -342,10 +323,6 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
342 |
outputs=[saveFileName, systemPromptTxt, chatbot]
|
343 |
)
|
344 |
|
345 |
-
refresh_history_args = dict(
|
346 |
-
fn=get_history_names, inputs=[gr.State(False), user_name], outputs=[historyFileSelectDropdown]
|
347 |
-
)
|
348 |
-
|
349 |
|
350 |
# Chatbot
|
351 |
cancelBtn.click(interrupt, [current_model], [])
|
@@ -364,7 +341,6 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
364 |
inputs=[current_model],
|
365 |
outputs=[chatbot, status_display],
|
366 |
show_progress=True,
|
367 |
-
_js='()=>{clearHistoryHtml();}',
|
368 |
)
|
369 |
|
370 |
retryBtn.click(**start_outputing_args).then(
|
@@ -415,7 +391,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
415 |
keyTxt.change(set_key, [current_model, keyTxt], [user_api_key, status_display], api_name="set_key").then(**get_usage_args)
|
416 |
keyTxt.submit(**get_usage_args)
|
417 |
single_turn_checkbox.change(set_single_turn, [current_model, single_turn_checkbox], None)
|
418 |
-
model_select_dropdown.change(get_model, [model_select_dropdown, lora_select_dropdown, user_api_key, temperature_slider, top_p_slider, systemPromptTxt, user_name], [current_model, status_display, chatbot, lora_select_dropdown
|
419 |
model_select_dropdown.change(toggle_like_btn_visibility, [model_select_dropdown], [like_dislike_area], show_progress=False)
|
420 |
lora_select_dropdown.change(get_model, [model_select_dropdown, lora_select_dropdown, user_api_key, temperature_slider, top_p_slider, systemPromptTxt, user_name], [current_model, status_display, chatbot], show_progress=True)
|
421 |
|
@@ -449,8 +425,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
449 |
downloadFile,
|
450 |
show_progress=True,
|
451 |
)
|
452 |
-
historyRefreshBtn.click(
|
453 |
-
historyDeleteBtn.click(delete_chat_history, [current_model, historyFileSelectDropdown, user_name], [status_display, historyFileSelectDropdown, chatbot], _js='(a,b,c)=>{return showConfirmationDialog(a, b, c);}')
|
454 |
historyFileSelectDropdown.change(**load_history_from_file_args)
|
455 |
downloadFile.change(upload_chat_history, [current_model, downloadFile, user_name], [saveFileName, systemPromptTxt, chatbot])
|
456 |
|
@@ -481,7 +456,6 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
|
|
481 |
[status_display],
|
482 |
show_progress=True,
|
483 |
)
|
484 |
-
checkUpdateBtn.click(fn=None, _js='()=>{manualCheckUpdate();}')
|
485 |
|
486 |
logging.info(
|
487 |
colorama.Back.GREEN
|
|
|
38 |
status_display = gr.Markdown(get_geoip(), elem_id="status_display")
|
39 |
with gr.Row(elem_id="float_display"):
|
40 |
user_info = gr.Markdown(value="getting user info...", elem_id="user_info")
|
41 |
+
|
42 |
+
with gr.Row().style(equal_height=True):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
with gr.Column(scale=5):
|
44 |
with gr.Row():
|
45 |
+
chatbot = gr.Chatbot(label="Chuanhu Chat", elem_id="chuanhu_chatbot").style(height="100%")
|
46 |
with gr.Row():
|
47 |
with gr.Column(min_width=225, scale=12):
|
48 |
user_input = gr.Textbox(
|
49 |
elem_id="user_input_tb",
|
50 |
+
show_label=False, placeholder=i18n("在这里输入")
|
51 |
+
).style(container=False)
|
|
|
52 |
with gr.Column(min_width=42, scale=1):
|
53 |
submitBtn = gr.Button(value="", variant="primary", elem_id="submit_btn")
|
54 |
cancelBtn = gr.Button(value="", variant="secondary", visible=False, elem_id="cancel_btn")
|
|
|
77 |
label="API-Key",
|
78 |
)
|
79 |
if multi_api_key:
|
80 |
+
usageTxt = gr.Markdown(i18n("多账号模式已开启,无需输入key,可直接开始对话"), elem_id="usage_display", elem_classes="insert_block")
|
81 |
else:
|
82 |
+
usageTxt = gr.Markdown(i18n("**发送消息** 或 **提交key** 以显示额度"), elem_id="usage_display", elem_classes="insert_block")
|
83 |
model_select_dropdown = gr.Dropdown(
|
84 |
label=i18n("选择模型"), choices=MODELS, multiselect=False, value=MODELS[DEFAULT_MODEL], interactive=True
|
85 |
)
|
|
|
87 |
label=i18n("选择LoRA模型"), choices=[], multiselect=False, interactive=True, visible=False
|
88 |
)
|
89 |
with gr.Row():
|
90 |
+
single_turn_checkbox = gr.Checkbox(label=i18n("单轮对话"), value=False)
|
91 |
+
use_websearch_checkbox = gr.Checkbox(label=i18n("使用在线搜索"), value=False)
|
92 |
language_select_dropdown = gr.Dropdown(
|
93 |
label=i18n("选择回复语言(针对搜索&索引功能)"),
|
94 |
choices=REPLY_LANGUAGES,
|
|
|
107 |
placeholder=i18n("在这里输入System Prompt..."),
|
108 |
label="System prompt",
|
109 |
value=INITIAL_SYSTEM_PROMPT,
|
110 |
+
lines=10,
|
111 |
+
).style(container=False)
|
112 |
with gr.Accordion(label=i18n("加载Prompt模板"), open=True):
|
113 |
with gr.Column():
|
114 |
with gr.Row():
|
|
|
118 |
choices=get_template_names(plain=True),
|
119 |
multiselect=False,
|
120 |
value=get_template_names(plain=True)[0],
|
121 |
+
).style(container=False)
|
|
|
122 |
with gr.Column(scale=1):
|
123 |
templateRefreshBtn = gr.Button(i18n("🔄 刷新"))
|
124 |
with gr.Row():
|
|
|
129 |
get_template_names(plain=True)[0], mode=1
|
130 |
),
|
131 |
multiselect=False,
|
132 |
+
).style(container=False)
|
|
|
133 |
|
134 |
with gr.Tab(label=i18n("保存/加载")):
|
135 |
with gr.Accordion(label=i18n("保存/加载对话历史记录"), open=True):
|
|
|
139 |
historyFileSelectDropdown = gr.Dropdown(
|
140 |
label=i18n("从列表中加载对话"),
|
141 |
choices=get_history_names(plain=True),
|
142 |
+
multiselect=False
|
|
|
143 |
)
|
144 |
+
with gr.Column(scale=1):
|
145 |
+
historyRefreshBtn = gr.Button(i18n("🔄 刷新"))
|
|
|
|
|
|
|
146 |
with gr.Row():
|
147 |
with gr.Column(scale=6):
|
148 |
saveFileName = gr.Textbox(
|
|
|
150 |
placeholder=i18n("设置文件名: 默认为.json,可选为.md"),
|
151 |
label=i18n("设置保存文件名"),
|
152 |
value=i18n("对话历史记录"),
|
153 |
+
).style(container=True)
|
|
|
154 |
with gr.Column(scale=1):
|
155 |
saveHistoryBtn = gr.Button(i18n("💾 保存对话"))
|
156 |
exportMarkdownBtn = gr.Button(i18n("📝 导出为Markdown"))
|
|
|
160 |
downloadFile = gr.File(interactive=True)
|
161 |
|
162 |
with gr.Tab(label=i18n("高级")):
|
163 |
+
gr.Markdown(i18n("# ⚠️ 务必谨慎更改 ⚠️\n\n如果无法使用请恢复默认设置"))
|
164 |
gr.HTML(get_html("appearance_switcher.html").format(label=i18n("切换亮暗色主题")), elem_classes="insert_block")
|
165 |
use_streaming_checkbox = gr.Checkbox(
|
166 |
+
label=i18n("实时传输回答"), value=True, visible=ENABLE_STREAMING_OPTION
|
167 |
)
|
|
|
|
|
168 |
with gr.Accordion(i18n("参数"), open=False):
|
169 |
temperature_slider = gr.Slider(
|
170 |
minimum=-0,
|
|
|
192 |
)
|
193 |
stop_sequence_txt = gr.Textbox(
|
194 |
show_label=True,
|
195 |
+
placeholder=i18n("在这里输入停止符,用英文逗号隔开..."),
|
196 |
label="stop",
|
197 |
value="",
|
198 |
lines=1,
|
|
|
244 |
lines=1,
|
245 |
)
|
246 |
|
247 |
+
with gr.Accordion(i18n("网络设置"), open=False, visible=False):
|
248 |
# 优先展示自定义的api_host
|
249 |
apihostTxt = gr.Textbox(
|
250 |
show_label=True,
|
|
|
252 |
label="API-Host",
|
253 |
value=config.api_host or shared.API_HOST,
|
254 |
lines=1,
|
|
|
255 |
)
|
256 |
changeAPIURLBtn = gr.Button(i18n("🔄 切换API地址"))
|
257 |
proxyTxt = gr.Textbox(
|
|
|
260 |
label=i18n("代理地址(示例:http://127.0.0.1:10809)"),
|
261 |
value="",
|
262 |
lines=2,
|
|
|
263 |
)
|
264 |
changeProxyBtn = gr.Button(i18n("🔄 设置代理地址"))
|
265 |
default_btn = gr.Button(i18n("🔙 恢复默认设置"))
|
|
|
323 |
outputs=[saveFileName, systemPromptTxt, chatbot]
|
324 |
)
|
325 |
|
|
|
|
|
|
|
|
|
326 |
|
327 |
# Chatbot
|
328 |
cancelBtn.click(interrupt, [current_model], [])
|
|
|
341 |
inputs=[current_model],
|
342 |
outputs=[chatbot, status_display],
|
343 |
show_progress=True,
|
|
|
344 |
)
|
345 |
|
346 |
retryBtn.click(**start_outputing_args).then(
|
|
|
391 |
keyTxt.change(set_key, [current_model, keyTxt], [user_api_key, status_display], api_name="set_key").then(**get_usage_args)
|
392 |
keyTxt.submit(**get_usage_args)
|
393 |
single_turn_checkbox.change(set_single_turn, [current_model, single_turn_checkbox], None)
|
394 |
+
model_select_dropdown.change(get_model, [model_select_dropdown, lora_select_dropdown, user_api_key, temperature_slider, top_p_slider, systemPromptTxt, user_name], [current_model, status_display, chatbot, lora_select_dropdown], show_progress=True, api_name="get_model")
|
395 |
model_select_dropdown.change(toggle_like_btn_visibility, [model_select_dropdown], [like_dislike_area], show_progress=False)
|
396 |
lora_select_dropdown.change(get_model, [model_select_dropdown, lora_select_dropdown, user_api_key, temperature_slider, top_p_slider, systemPromptTxt, user_name], [current_model, status_display, chatbot], show_progress=True)
|
397 |
|
|
|
425 |
downloadFile,
|
426 |
show_progress=True,
|
427 |
)
|
428 |
+
historyRefreshBtn.click(get_history_names, [gr.State(False), user_name], [historyFileSelectDropdown])
|
|
|
429 |
historyFileSelectDropdown.change(**load_history_from_file_args)
|
430 |
downloadFile.change(upload_chat_history, [current_model, downloadFile, user_name], [saveFileName, systemPromptTxt, chatbot])
|
431 |
|
|
|
456 |
[status_display],
|
457 |
show_progress=True,
|
458 |
)
|
|
|
459 |
|
460 |
logging.info(
|
461 |
colorama.Back.GREEN
|
Dockerfile
CHANGED
@@ -1,18 +1,15 @@
|
|
1 |
-
FROM python:3.9
|
2 |
-
RUN apt-get update
|
3 |
-
&& apt-get install -y build-essential \
|
4 |
-
&& apt-get clean \
|
5 |
-
&& rm -rf /var/lib/apt/lists/*
|
6 |
COPY requirements.txt .
|
7 |
COPY requirements_advanced.txt .
|
8 |
-
RUN pip install --user
|
9 |
-
# RUN pip install --user
|
10 |
|
11 |
-
FROM python:3.9
|
12 |
-
|
13 |
COPY --from=builder /root/.local /root/.local
|
14 |
ENV PATH=/root/.local/bin:$PATH
|
15 |
COPY . /app
|
16 |
WORKDIR /app
|
17 |
-
ENV dockerrun
|
18 |
-
CMD ["python3", "-u", "ChuanhuChatbot.py","2>&1", "|", "tee", "/var/log/application.log"]
|
|
|
1 |
+
FROM python:3.9 as builder
|
2 |
+
RUN apt-get update && apt-get install -y build-essential
|
|
|
|
|
|
|
3 |
COPY requirements.txt .
|
4 |
COPY requirements_advanced.txt .
|
5 |
+
RUN pip install --user -r requirements.txt
|
6 |
+
# RUN pip install --user -r requirements_advanced.txt
|
7 |
|
8 |
+
FROM python:3.9
|
9 |
+
MAINTAINER iskoldt
|
10 |
COPY --from=builder /root/.local /root/.local
|
11 |
ENV PATH=/root/.local/bin:$PATH
|
12 |
COPY . /app
|
13 |
WORKDIR /app
|
14 |
+
ENV dockerrun yes
|
15 |
+
CMD ["python3", "-u", "ChuanhuChatbot.py", "2>&1", "|", "tee", "/var/log/application.log"]
|
README.md
CHANGED
@@ -4,10 +4,11 @@ emoji: 🐯
|
|
4 |
colorFrom: green
|
5 |
colorTo: red
|
6 |
sdk: gradio
|
7 |
-
sdk_version: 3.
|
8 |
app_file: ChuanhuChatbot.py
|
9 |
pinned: false
|
10 |
license: gpl-3.0
|
|
|
11 |
---
|
12 |
|
13 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
4 |
colorFrom: green
|
5 |
colorTo: red
|
6 |
sdk: gradio
|
7 |
+
sdk_version: 3.33.1
|
8 |
app_file: ChuanhuChatbot.py
|
9 |
pinned: false
|
10 |
license: gpl-3.0
|
11 |
+
duplicated_from: JohnSmith9982/ChuanhuChatGPT
|
12 |
---
|
13 |
|
14 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
README_origin.md
DELETED
@@ -1,142 +0,0 @@
|
|
1 |
-
<div align="right">
|
2 |
-
<!-- 语言: -->
|
3 |
-
简体中文 | <a title="English" href="./readme/README_en.md">English</a> | <a title="Japanese" href="./readme/README_ja.md">日本語</a>
|
4 |
-
</div>
|
5 |
-
|
6 |
-
<h1 align="center">川虎 Chat 🐯 Chuanhu Chat</h1>
|
7 |
-
<div align="center">
|
8 |
-
<a href="https://github.com/GaiZhenBiao/ChuanhuChatGPT">
|
9 |
-
<img src="https://github.com/GaiZhenbiao/ChuanhuChatGPT/assets/70903329/aca3a7ec-4f1d-4667-890c-a6f47bf08f63" alt="Logo" height="156">
|
10 |
-
</a>
|
11 |
-
|
12 |
-
<p align="center">
|
13 |
-
<h3>为ChatGPT等多种LLM提供了一个轻快好用的Web图形界面和众多附加功能</h3>
|
14 |
-
<p align="center">
|
15 |
-
<a href="https://github.com/GaiZhenbiao/ChuanhuChatGPT/blob/main/LICENSE">
|
16 |
-
<img alt="Tests Passing" src="https://img.shields.io/github/license/GaiZhenbiao/ChuanhuChatGPT" />
|
17 |
-
</a>
|
18 |
-
<a href="https://gradio.app/">
|
19 |
-
<img alt="GitHub Contributors" src="https://img.shields.io/badge/Base-Gradio-fb7d1a?style=flat" />
|
20 |
-
</a>
|
21 |
-
<a href="https://t.me/tkdifferent">
|
22 |
-
<img alt="GitHub pull requests" src="https://img.shields.io/badge/Telegram-Group-blue.svg?logo=telegram" />
|
23 |
-
</a>
|
24 |
-
<p>
|
25 |
-
流式传输 / 无限对话 / 保存对话 / 预设Prompt集 / 联网搜索 / 根据文件回答 <br />
|
26 |
-
渲染LaTeX / 渲染表格 / 代码高亮 / 自动亮暗色切换 / 自适应界面 / “小而美”的体验 <br />
|
27 |
-
自定义api-Host / 多参数可调 / 多API Key均衡负载 / 多用户显示 / 适配GPT-4 / 支持本地部署LLM
|
28 |
-
</p>
|
29 |
-
<a href="https://www.bilibili.com/video/BV1mo4y1r7eE"><strong>视频教程</strong></a>
|
30 |
-
·
|
31 |
-
<a href="https://www.bilibili.com/video/BV1184y1w7aP"><strong>2.0介绍视频</strong></a>
|
32 |
-
||
|
33 |
-
<a href="https://huggingface.co/spaces/JohnSmith9982/ChuanhuChatGPT"><strong>在线体验</strong></a>
|
34 |
-
·
|
35 |
-
<a href="https://huggingface.co/login?next=%2Fspaces%2FJohnSmith9982%2FChuanhuChatGPT%3Fduplicate%3Dtrue"><strong>一键部署</strong></a>
|
36 |
-
</p>
|
37 |
-
<p align="center">
|
38 |
-
<img alt="Animation Demo" src="https://user-images.githubusercontent.com/51039745/226255695-6b17ff1f-ea8d-464f-b69b-a7b6b68fffe8.gif" />
|
39 |
-
</p>
|
40 |
-
</p>
|
41 |
-
</div>
|
42 |
-
|
43 |
-
## 目录
|
44 |
-
|
45 |
-
| [支持模型](#支持模型) | [使用技巧](#使用技巧) | [安装方式](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程) | [常见问题](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/常见问题) | [给作者买可乐🥤](#捐款) |
|
46 |
-
| ------------------ | ------------------ | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------- |
|
47 |
-
|
48 |
-
## 支持模型
|
49 |
-
|
50 |
-
**通过API调用的语言模型**:
|
51 |
-
|
52 |
-
- [ChatGPT](https://chat.openai.com) ([GPT-4](https://openai.com/product/gpt-4))
|
53 |
-
- [Google PaLM](https://developers.generativeai.google/products/palm)
|
54 |
-
- [Inspur Yuan 1.0](https://air.inspur.com/home)
|
55 |
-
- [MiniMax](https://api.minimax.chat/)
|
56 |
-
- [XMChat](https://github.com/MILVLG/xmchat)
|
57 |
-
|
58 |
-
**本地部署语言模型**:
|
59 |
-
|
60 |
-
- [ChatGLM](https://github.com/THUDM/ChatGLM-6B) ([ChatGLM2](https://github.com/THUDM/ChatGLM2-6B))
|
61 |
-
- [LLaMA](https://github.com/facebookresearch/llama)
|
62 |
-
- [StableLM](https://github.com/Stability-AI/StableLM)
|
63 |
-
- [MOSS](https://github.com/OpenLMLab/MOSS)
|
64 |
-
|
65 |
-
## 使用技巧
|
66 |
-
|
67 |
-
- 使用System Prompt可以很有效地设定前提条件。
|
68 |
-
- 使用Prompt模板功能时,选择Prompt模板集合文件,然后从下拉菜单中选择想要的prompt。
|
69 |
-
- 如果回答不满意,可以使用 `重新生成`按钮再试一次
|
70 |
-
- 输入框支持换行,按 `shift enter`即可。
|
71 |
-
- 可以在输入框按上下箭头在输入历史之间切换
|
72 |
-
- 部署到服务器:在 `config.json` 中设置 `"server_name": "0.0.0.0", "server_port": <你的端口号>,`。
|
73 |
-
- 获取公共链接:在 `config.json` 中设置 `"share": true,`。注意程序必须在运行,才能通过公共链接访问。
|
74 |
-
- 在Hugging Face上使用:建议在右上角 **复制Space** 再使用,这样App反应可能会快一点。
|
75 |
-
|
76 |
-
## 快速上手
|
77 |
-
|
78 |
-
```shell
|
79 |
-
git clone https://github.com/GaiZhenbiao/ChuanhuChatGPT.git
|
80 |
-
cd ChuanhuChatGPT
|
81 |
-
pip install -r requirements.txt
|
82 |
-
```
|
83 |
-
|
84 |
-
然后,在项目文件夹中复制一份 `config_example.json`,并将其重命名为 `config.json`,在其中填入 `API-Key` 等设置。
|
85 |
-
|
86 |
-
```shell
|
87 |
-
python ChuanhuChatbot.py
|
88 |
-
```
|
89 |
-
|
90 |
-
一个浏览器窗口将会自动打开,此时您将可以使用 **川虎Chat** 与ChatGPT或其他模型进行对话。
|
91 |
-
|
92 |
-
> **Note**
|
93 |
-
>
|
94 |
-
> 具体详尽的安装教程和使用教程请查看[本项目的wiki页面](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程)。
|
95 |
-
|
96 |
-
## 疑难杂症解决
|
97 |
-
|
98 |
-
在遇到各种问题查阅相关信息前,您可以先尝试手动拉取本项目的最新更改并更新依赖库,然后重试。步骤为:
|
99 |
-
|
100 |
-
1. 点击网页上的 `Download ZIP` 下载最新代码,或
|
101 |
-
```shell
|
102 |
-
git pull https://github.com/GaiZhenbiao/ChuanhuChatGPT.git main -f
|
103 |
-
```
|
104 |
-
2. 尝试再次��装依赖(可能本项目引入了新的依赖)
|
105 |
-
```
|
106 |
-
pip install -r requirements.txt
|
107 |
-
```
|
108 |
-
|
109 |
-
很多时候,这样就可以解决问题。
|
110 |
-
|
111 |
-
如果问题仍然存在,请查阅该页面:[常见问题](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/常见问题)
|
112 |
-
|
113 |
-
该页面列出了**几乎所有**您可能遇到的各种问题,包括如何配置代理,以及遇到问题后您该采取的措施,**请务必认真阅读**。
|
114 |
-
|
115 |
-
## 了解更多
|
116 |
-
|
117 |
-
若需了解更多信息,请查看我们的 [wiki](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki):
|
118 |
-
|
119 |
-
- [想要做出贡献?](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/贡献指南)
|
120 |
-
- [项目更新情况?](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/更新日志)
|
121 |
-
- [二次开发许可?](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用许可)
|
122 |
-
- [如何引用项目?](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用许可#如何引用该项目)
|
123 |
-
|
124 |
-
## Starchart
|
125 |
-
|
126 |
-
[![Star History Chart](https://api.star-history.com/svg?repos=GaiZhenbiao/ChuanhuChatGPT&type=Date)](https://star-history.com/#GaiZhenbiao/ChuanhuChatGPT&Date)
|
127 |
-
|
128 |
-
## Contributors
|
129 |
-
|
130 |
-
<a href="https://github.com/GaiZhenbiao/ChuanhuChatGPT/graphs/contributors">
|
131 |
-
<img src="https://contrib.rocks/image?repo=GaiZhenbiao/ChuanhuChatGPT" />
|
132 |
-
</a>
|
133 |
-
|
134 |
-
## 捐款
|
135 |
-
|
136 |
-
🐯如果觉得这个软件对你有所帮助,欢迎请作者喝可乐、喝咖啡~
|
137 |
-
|
138 |
-
联系作者:请去[我的bilibili账号](https://space.bilibili.com/29125536)私信我。
|
139 |
-
|
140 |
-
<a href="https://www.buymeacoffee.com/ChuanhuChat" ><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=ChuanhuChat&button_colour=219d53&font_colour=ffffff&font_family=Poppins&outline_colour=ffffff&coffee_colour=FFDD00" alt="Buy Me A Coffee" width="250"></a>
|
141 |
-
|
142 |
-
<img width="250" alt="image" src="https://user-images.githubusercontent.com/51039745/226920291-e8ec0b0a-400f-4c20-ac13-dafac0c3aeeb.JPG">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assets/Kelpy-Codos.js
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// ==UserScript==
|
2 |
+
// @name Kelpy Codos
|
3 |
+
// @namespace https://github.com/Keldos-Li/Kelpy-Codos
|
4 |
+
// @version 1.0.5
|
5 |
+
// @author Keldos; https://keldos.me/
|
6 |
+
// @description Add copy button to PRE tags before CODE tag, for Chuanhu ChatGPT especially.
|
7 |
+
// Based on Chuanhu ChatGPT version: ac04408 (2023-3-22)
|
8 |
+
// @license GPL-3.0
|
9 |
+
// @grant none
|
10 |
+
// ==/UserScript==
|
11 |
+
|
12 |
+
(function () {
|
13 |
+
'use strict';
|
14 |
+
|
15 |
+
function addCopyButton(pre) {
|
16 |
+
var code = pre.querySelector('code');
|
17 |
+
if (!code) {
|
18 |
+
return; // 如果没有找到 <code> 元素,则不添加按钮
|
19 |
+
}
|
20 |
+
var firstChild = code.firstChild;
|
21 |
+
if (!firstChild) {
|
22 |
+
return; // 如果 <code> 元素没有子节点,则不添加按钮
|
23 |
+
}
|
24 |
+
var button = document.createElement('button');
|
25 |
+
button.textContent = '\uD83D\uDCCE'; // 使用 📎 符号作为“复制”按钮的文本
|
26 |
+
button.style.position = 'relative';
|
27 |
+
button.style.float = 'right';
|
28 |
+
button.style.fontSize = '1em'; // 可选:调整按钮大小
|
29 |
+
button.style.background = 'none'; // 可选:去掉背景颜色
|
30 |
+
button.style.border = 'none'; // 可选:去掉边框
|
31 |
+
button.style.cursor = 'pointer'; // 可选:显示指针样式
|
32 |
+
button.addEventListener('click', function () {
|
33 |
+
var range = document.createRange();
|
34 |
+
range.selectNodeContents(code);
|
35 |
+
range.setStartBefore(firstChild); // 将范围设置为第一个子节点之前
|
36 |
+
var selection = window.getSelection();
|
37 |
+
selection.removeAllRanges();
|
38 |
+
selection.addRange(range);
|
39 |
+
|
40 |
+
try {
|
41 |
+
var success = document.execCommand('copy');
|
42 |
+
if (success) {
|
43 |
+
button.textContent = '\u2714';
|
44 |
+
setTimeout(function () {
|
45 |
+
button.textContent = '\uD83D\uDCCE'; // 恢复按钮为“复制”
|
46 |
+
}, 2000);
|
47 |
+
} else {
|
48 |
+
button.textContent = '\u2716';
|
49 |
+
}
|
50 |
+
} catch (e) {
|
51 |
+
console.error(e);
|
52 |
+
button.textContent = '\u2716';
|
53 |
+
}
|
54 |
+
|
55 |
+
selection.removeAllRanges();
|
56 |
+
});
|
57 |
+
code.insertBefore(button, firstChild); // 将按钮插入到第一个子元素之前
|
58 |
+
}
|
59 |
+
|
60 |
+
function handleNewElements(mutationsList, observer) {
|
61 |
+
for (var mutation of mutationsList) {
|
62 |
+
if (mutation.type === 'childList') {
|
63 |
+
for (var node of mutation.addedNodes) {
|
64 |
+
if (node.nodeName === 'PRE') {
|
65 |
+
addCopyButton(node);
|
66 |
+
}
|
67 |
+
}
|
68 |
+
}
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
var observer = new MutationObserver(handleNewElements);
|
73 |
+
observer.observe(document.documentElement, { childList: true, subtree: true });
|
74 |
+
|
75 |
+
document.querySelectorAll('pre').forEach(addCopyButton);
|
76 |
+
})();
|
assets/custom.css
CHANGED
@@ -7,11 +7,8 @@
|
|
7 |
--message-user-background-color-dark: #26B561;
|
8 |
--message-bot-background-color-light: #FFFFFF;
|
9 |
--message-bot-background-color-dark: #2C2C2C;
|
10 |
-
--switch-checkbox-color-light: #e5e7eb;
|
11 |
-
--switch-checkbox-color-dark: #515151;
|
12 |
}
|
13 |
|
14 |
-
|
15 |
#app_title {
|
16 |
font-weight: var(--prose-header-text-weight);
|
17 |
font-size: var(--text-xxl);
|
@@ -25,19 +22,6 @@
|
|
25 |
margin: 32px 0 4px 0;
|
26 |
}
|
27 |
|
28 |
-
/* 解决container=False时的错误填充 */
|
29 |
-
div.form {
|
30 |
-
background: none !important;
|
31 |
-
}
|
32 |
-
|
33 |
-
/* 高级页面 */
|
34 |
-
#advanced_warning {
|
35 |
-
display: flex;
|
36 |
-
flex-wrap: wrap;
|
37 |
-
flex-direction: column;
|
38 |
-
align-content: center;
|
39 |
-
}
|
40 |
-
|
41 |
/* gradio的页脚信息 */
|
42 |
footer {
|
43 |
/* display: none !important; */
|
@@ -59,74 +43,21 @@ footer {
|
|
59 |
position: absolute;
|
60 |
max-height: 30px;
|
61 |
}
|
62 |
-
#toast-update {
|
63 |
-
position: absolute;
|
64 |
-
display: flex;
|
65 |
-
top: -500px;
|
66 |
-
width: 100%;
|
67 |
-
justify-content: center;
|
68 |
-
z-index: var(--layer-top);
|
69 |
-
transition: top 0.3s ease-out;
|
70 |
-
}
|
71 |
-
#check-chuanhu-update {
|
72 |
-
position: absolute;
|
73 |
-
align-items: center;
|
74 |
-
display: flex;
|
75 |
-
flex-direction: column;
|
76 |
-
justify-content: center;
|
77 |
-
margin: var(--size-6) var(--size-4);
|
78 |
-
box-shadow: var(--shadow-drop-lg);
|
79 |
-
border: 1px solid var(--block-label-border-color);
|
80 |
-
border-radius: var(--container-radius);
|
81 |
-
background: var(--background-fill-primary);
|
82 |
-
padding: var(--size-4) var(--size-6);
|
83 |
-
min-width: 360px;
|
84 |
-
max-width: 480px;
|
85 |
-
overflow: hidden;
|
86 |
-
pointer-events: auto;
|
87 |
-
}
|
88 |
-
#version-info-title {
|
89 |
-
font-size: 1.2em;
|
90 |
-
font-weight: bold;
|
91 |
-
text-align: start;
|
92 |
-
width: 100%;
|
93 |
-
}
|
94 |
-
#release-note-wrap {
|
95 |
-
width: 100%;
|
96 |
-
max-width: 400px;
|
97 |
-
height: 120px;
|
98 |
-
border: solid 1px var(--border-color-primary);
|
99 |
-
overflow: auto;
|
100 |
-
padding: 0 8px;
|
101 |
-
}
|
102 |
-
#release-note-wrap.hideK {
|
103 |
-
display: none;
|
104 |
-
}
|
105 |
-
.btn-update-group {
|
106 |
-
display: flex;
|
107 |
-
justify-content: space-evenly;
|
108 |
-
align-items: center;
|
109 |
-
width: 100%;
|
110 |
-
padding-top: 10px;
|
111 |
-
}
|
112 |
-
.btn-update-group.hideK {
|
113 |
-
display: none;
|
114 |
-
}
|
115 |
/* user_info */
|
116 |
-
#user_info
|
117 |
white-space: nowrap;
|
118 |
-
position: absolute; left: 8em; top: .
|
119 |
z-index: var(--layer-2);
|
120 |
box-shadow: var(--block-shadow);
|
121 |
-
border: none
|
122 |
background: var(--color-accent);
|
123 |
padding: var(--block-label-padding);
|
124 |
font-size: var(--block-label-text-size); line-height: var(--line-sm);
|
125 |
-
width: auto;
|
126 |
opacity: 1;
|
127 |
transition: opacity 0.3s ease-in-out;
|
128 |
}
|
129 |
-
#user_info
|
130 |
opacity: 0;
|
131 |
}
|
132 |
#user_info p {
|
@@ -163,7 +94,7 @@ footer {
|
|
163 |
.insert_block {
|
164 |
position: relative;
|
165 |
margin: 0;
|
166 |
-
padding:
|
167 |
box-shadow: var(--block-shadow);
|
168 |
border-width: var(--block-border-width);
|
169 |
border-color: var(--block-border-color);
|
@@ -201,42 +132,13 @@ footer {
|
|
201 |
line-height: 20px;
|
202 |
}
|
203 |
|
204 |
-
|
205 |
-
#apSwitch input[type="checkbox"] {
|
206 |
-
margin: 0 !important;
|
207 |
-
}
|
208 |
-
#apSwitch label.apSwitch {
|
209 |
-
display: flex;
|
210 |
-
align-items: center;
|
211 |
-
cursor: pointer;
|
212 |
-
color: var(--body-text-color);
|
213 |
-
font-weight: var(--checkbox-label-text-weight);
|
214 |
-
font-size: var(--checkbox-label-text-size);
|
215 |
-
line-height: var(--line-md);
|
216 |
-
margin: 2px 0 !important;
|
217 |
-
}
|
218 |
-
input[type="checkbox"]#apSwitch_checkbox::before {
|
219 |
-
background: none !important;
|
220 |
-
content: '🌞';
|
221 |
-
border: none !important;
|
222 |
-
box-shadow: none !important;
|
223 |
-
font-size: 22px;
|
224 |
-
top: -4.4px;
|
225 |
-
left: -1px;
|
226 |
-
}
|
227 |
-
input:checked[type="checkbox"]#apSwitch_checkbox::before {
|
228 |
-
content: '🌚';
|
229 |
-
left: 16px;
|
230 |
-
}
|
231 |
-
|
232 |
-
/* .apSwitch {
|
233 |
top: 2px;
|
234 |
display: inline-block;
|
235 |
-
height:
|
236 |
position: relative;
|
237 |
-
width:
|
238 |
-
border-radius:
|
239 |
-
box-shadow: inset 0 0 1px 0 rgba(0,0,0,0.05), inset 0 0 2px 0 rgba(0,0,0,0.08) !important;
|
240 |
}
|
241 |
.apSwitch input {
|
242 |
display: none !important;
|
@@ -250,11 +152,12 @@ input:checked[type="checkbox"]#apSwitch_checkbox::before {
|
|
250 |
right: 0;
|
251 |
top: 0;
|
252 |
transition: .4s;
|
253 |
-
font-size:
|
254 |
-
border-radius:
|
255 |
}
|
256 |
.apSlider::before {
|
257 |
-
|
|
|
258 |
position: absolute;
|
259 |
transition: .4s;
|
260 |
content: "🌞";
|
@@ -263,63 +166,8 @@ input:checked + .apSlider {
|
|
263 |
background-color: var(--primary-600);
|
264 |
}
|
265 |
input:checked + .apSlider::before {
|
266 |
-
transform: translateX(
|
267 |
content:"🌚";
|
268 |
-
} */
|
269 |
-
|
270 |
-
.switch_checkbox label {
|
271 |
-
flex-direction: row-reverse;
|
272 |
-
justify-content: space-between;
|
273 |
-
}
|
274 |
-
.switch_checkbox input[type="checkbox"] + span {
|
275 |
-
margin-left: 0 !important;
|
276 |
-
}
|
277 |
-
|
278 |
-
.switch_checkbox input[type="checkbox"] {
|
279 |
-
-moz-appearance: none;
|
280 |
-
appearance: none;
|
281 |
-
-webkit-appearance: none;
|
282 |
-
outline: none;
|
283 |
-
}
|
284 |
-
|
285 |
-
.switch_checkbox input[type="checkbox"] {
|
286 |
-
display: inline-block !important;
|
287 |
-
position: relative !important;
|
288 |
-
border: none !important;
|
289 |
-
outline: none;
|
290 |
-
width: 40px !important;
|
291 |
-
height: 22px !important;
|
292 |
-
border-radius: 11px !important;
|
293 |
-
background-image: none !important;
|
294 |
-
box-shadow: inset 0 0 1px 0 rgba(0,0,0,0.05), inset 0 0 2px 0 rgba(0,0,0,0.08) !important;
|
295 |
-
background-image: none !important;
|
296 |
-
background-color: var(--switch-checkbox-color-light) !important;
|
297 |
-
transition: .2s ease background-color;
|
298 |
-
}
|
299 |
-
.dark .switch_checkbox input[type="checkbox"] {
|
300 |
-
background-color: var(--switch-checkbox-color-dark) !important;
|
301 |
-
}
|
302 |
-
.switch_checkbox input[type="checkbox"]::before {
|
303 |
-
content: "";
|
304 |
-
position: absolute;
|
305 |
-
width: 22px;
|
306 |
-
height: 22px;
|
307 |
-
top: 0;
|
308 |
-
left: 0;
|
309 |
-
background: #FFFFFF;
|
310 |
-
border: 0.5px solid rgba(0,0,0,0.02);
|
311 |
-
box-shadow: 0 0 0 0 rgba(0,0,0,0.15), 0 1px 0 0 rgba(0,0,0,0.05);
|
312 |
-
transform: scale(0.9);
|
313 |
-
border-radius: 11px !important;
|
314 |
-
transition: .4s ease all;
|
315 |
-
box-shadow: var(--input-shadow);
|
316 |
-
}
|
317 |
-
.switch_checkbox input:checked[type="checkbox"] {
|
318 |
-
background-color: var(--primary-600) !important;
|
319 |
-
}
|
320 |
-
.switch_checkbox input:checked[type="checkbox"]::before {
|
321 |
-
background-color: #fff;
|
322 |
-
left: 18px;
|
323 |
}
|
324 |
|
325 |
/* Override Slider Styles (for webkit browsers like Safari and Chrome)
|
@@ -356,45 +204,6 @@ input[type=range]::-webkit-slider-runnable-track {
|
|
356 |
background: transparent;
|
357 |
}
|
358 |
|
359 |
-
hr.append-display {
|
360 |
-
margin: 8px 0;
|
361 |
-
border: none;
|
362 |
-
height: 1px;
|
363 |
-
border-top-width: 0;
|
364 |
-
background-image: linear-gradient(to right, rgba(50,50,50, 0.1), rgba(150, 150, 150, 0.8), rgba(50,50,50, 0.1));
|
365 |
-
}
|
366 |
-
.source-a {
|
367 |
-
font-size: 0.8em;
|
368 |
-
max-width: 100%;
|
369 |
-
margin: 0;
|
370 |
-
display: flex;
|
371 |
-
flex-direction: row;
|
372 |
-
flex-wrap: wrap;
|
373 |
-
align-items: center;
|
374 |
-
/* background-color: #dddddd88; */
|
375 |
-
border-radius: 1.5rem;
|
376 |
-
padding: 0.2em;
|
377 |
-
}
|
378 |
-
.source-a a {
|
379 |
-
display: inline-block;
|
380 |
-
background-color: #aaaaaa50;
|
381 |
-
border-radius: 1rem;
|
382 |
-
padding: 0.5em;
|
383 |
-
text-align: center;
|
384 |
-
text-overflow: ellipsis;
|
385 |
-
overflow: hidden;
|
386 |
-
min-width: 20%;
|
387 |
-
white-space: nowrap;
|
388 |
-
margin: 0.2rem 0.1rem;
|
389 |
-
text-decoration: none !important;
|
390 |
-
flex: 1;
|
391 |
-
transition: flex 0.5s;
|
392 |
-
}
|
393 |
-
.source-a a:hover {
|
394 |
-
background-color: #aaaaaa20;
|
395 |
-
flex: 2;
|
396 |
-
}
|
397 |
-
|
398 |
#submit_btn, #cancel_btn {
|
399 |
height: 42px !important;
|
400 |
}
|
@@ -440,7 +249,7 @@ ol:not(.options), ul:not(.options) {
|
|
440 |
#chuanhu_chatbot {
|
441 |
height: calc(100vh - 200px);
|
442 |
}
|
443 |
-
#chuanhu_chatbot
|
444 |
max-height: calc(100vh - 200px - var(--line-sm)*1rem - 2*var(--block-label-margin) );
|
445 |
}
|
446 |
}
|
@@ -449,7 +258,7 @@ ol:not(.options), ul:not(.options) {
|
|
449 |
#chuanhu_chatbot {
|
450 |
height: calc(100vh - 140px);
|
451 |
}
|
452 |
-
#chuanhu_chatbot
|
453 |
max-height: calc(100vh - 140px - var(--line-sm)*1rem - 2*var(--block-label-margin) );
|
454 |
}
|
455 |
[data-testid = "bot"] {
|
@@ -459,7 +268,7 @@ ol:not(.options), ul:not(.options) {
|
|
459 |
letter-spacing: -1px; font-size: 22px;
|
460 |
}
|
461 |
}
|
462 |
-
#chuanhu_chatbot
|
463 |
overflow-x: hidden;
|
464 |
}
|
465 |
/* 对话气泡 */
|
@@ -555,7 +364,7 @@ ol:not(.options), ul:not(.options) {
|
|
555 |
}
|
556 |
|
557 |
/* history message */
|
558 |
-
.
|
559 |
padding: 10px !important;
|
560 |
}
|
561 |
.history-message {
|
@@ -574,7 +383,7 @@ ol:not(.options), ul:not(.options) {
|
|
574 |
.history-message>.message {
|
575 |
margin-bottom: 16px;
|
576 |
}
|
577 |
-
.
|
578 |
content: "";
|
579 |
display: block;
|
580 |
height: 2px;
|
@@ -583,7 +392,7 @@ ol:not(.options), ul:not(.options) {
|
|
583 |
margin-top: -10px;
|
584 |
clear: both;
|
585 |
}
|
586 |
-
.
|
587 |
content: "仅供查看";
|
588 |
display: block;
|
589 |
text-align: center;
|
|
|
7 |
--message-user-background-color-dark: #26B561;
|
8 |
--message-bot-background-color-light: #FFFFFF;
|
9 |
--message-bot-background-color-dark: #2C2C2C;
|
|
|
|
|
10 |
}
|
11 |
|
|
|
12 |
#app_title {
|
13 |
font-weight: var(--prose-header-text-weight);
|
14 |
font-size: var(--text-xxl);
|
|
|
22 |
margin: 32px 0 4px 0;
|
23 |
}
|
24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
/* gradio的页脚信息 */
|
26 |
footer {
|
27 |
/* display: none !important; */
|
|
|
43 |
position: absolute;
|
44 |
max-height: 30px;
|
45 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
/* user_info */
|
47 |
+
#user_info {
|
48 |
white-space: nowrap;
|
49 |
+
position: absolute; left: 8em; top: .2em;
|
50 |
z-index: var(--layer-2);
|
51 |
box-shadow: var(--block-shadow);
|
52 |
+
border: none; border-radius: var(--block-label-radius);
|
53 |
background: var(--color-accent);
|
54 |
padding: var(--block-label-padding);
|
55 |
font-size: var(--block-label-text-size); line-height: var(--line-sm);
|
56 |
+
width: auto; min-height: 30px!important;
|
57 |
opacity: 1;
|
58 |
transition: opacity 0.3s ease-in-out;
|
59 |
}
|
60 |
+
#user_info .wrap {
|
61 |
opacity: 0;
|
62 |
}
|
63 |
#user_info p {
|
|
|
94 |
.insert_block {
|
95 |
position: relative;
|
96 |
margin: 0;
|
97 |
+
padding: .5em 1em;
|
98 |
box-shadow: var(--block-shadow);
|
99 |
border-width: var(--block-border-width);
|
100 |
border-color: var(--block-border-color);
|
|
|
132 |
line-height: 20px;
|
133 |
}
|
134 |
|
135 |
+
.apSwitch {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
136 |
top: 2px;
|
137 |
display: inline-block;
|
138 |
+
height: 24px;
|
139 |
position: relative;
|
140 |
+
width: 48px;
|
141 |
+
border-radius: 12px;
|
|
|
142 |
}
|
143 |
.apSwitch input {
|
144 |
display: none !important;
|
|
|
152 |
right: 0;
|
153 |
top: 0;
|
154 |
transition: .4s;
|
155 |
+
font-size: 18px;
|
156 |
+
border-radius: 12px;
|
157 |
}
|
158 |
.apSlider::before {
|
159 |
+
bottom: -1.5px;
|
160 |
+
left: 1px;
|
161 |
position: absolute;
|
162 |
transition: .4s;
|
163 |
content: "🌞";
|
|
|
166 |
background-color: var(--primary-600);
|
167 |
}
|
168 |
input:checked + .apSlider::before {
|
169 |
+
transform: translateX(23px);
|
170 |
content:"🌚";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
171 |
}
|
172 |
|
173 |
/* Override Slider Styles (for webkit browsers like Safari and Chrome)
|
|
|
204 |
background: transparent;
|
205 |
}
|
206 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
207 |
#submit_btn, #cancel_btn {
|
208 |
height: 42px !important;
|
209 |
}
|
|
|
249 |
#chuanhu_chatbot {
|
250 |
height: calc(100vh - 200px);
|
251 |
}
|
252 |
+
#chuanhu_chatbot .wrap {
|
253 |
max-height: calc(100vh - 200px - var(--line-sm)*1rem - 2*var(--block-label-margin) );
|
254 |
}
|
255 |
}
|
|
|
258 |
#chuanhu_chatbot {
|
259 |
height: calc(100vh - 140px);
|
260 |
}
|
261 |
+
#chuanhu_chatbot .wrap {
|
262 |
max-height: calc(100vh - 140px - var(--line-sm)*1rem - 2*var(--block-label-margin) );
|
263 |
}
|
264 |
[data-testid = "bot"] {
|
|
|
268 |
letter-spacing: -1px; font-size: 22px;
|
269 |
}
|
270 |
}
|
271 |
+
#chuanhu_chatbot .wrap {
|
272 |
overflow-x: hidden;
|
273 |
}
|
274 |
/* 对话气泡 */
|
|
|
364 |
}
|
365 |
|
366 |
/* history message */
|
367 |
+
.wrap>.history-message {
|
368 |
padding: 10px !important;
|
369 |
}
|
370 |
.history-message {
|
|
|
383 |
.history-message>.message {
|
384 |
margin-bottom: 16px;
|
385 |
}
|
386 |
+
.wrap>.history-message::after {
|
387 |
content: "";
|
388 |
display: block;
|
389 |
height: 2px;
|
|
|
392 |
margin-top: -10px;
|
393 |
clear: both;
|
394 |
}
|
395 |
+
.wrap>.history-message>:last-child::after {
|
396 |
content: "仅供查看";
|
397 |
display: block;
|
398 |
text-align: center;
|
assets/custom.js
CHANGED
@@ -15,60 +15,26 @@ var appTitleDiv = null;
|
|
15 |
var chatbot = null;
|
16 |
var chatbotWrap = null;
|
17 |
var apSwitch = null;
|
|
|
18 |
var messageBotDivs = null;
|
19 |
var loginUserForm = null;
|
20 |
var logginUser = null;
|
21 |
-
var updateToast = null;
|
22 |
-
var sendBtn = null;
|
23 |
-
var cancelBtn = null;
|
24 |
-
var sliders = null;
|
25 |
|
26 |
var userLogged = false;
|
27 |
var usernameGotten = false;
|
28 |
var historyLoaded = false;
|
29 |
-
var updateInfoGotten = false;
|
30 |
-
var isLatestVersion = localStorage.getItem('isLatestVersion') || false;
|
31 |
|
32 |
var ga = document.getElementsByTagName("gradio-app");
|
33 |
var targetNode = ga[0];
|
34 |
var isInIframe = (window.self !== window.top);
|
35 |
var language = navigator.language.slice(0,2);
|
36 |
-
var currentTime = new Date().getTime();
|
37 |
|
38 |
-
// i18n
|
39 |
var forView_i18n = {
|
40 |
'zh': "仅供查看",
|
41 |
'en': "For viewing only",
|
42 |
'ja': "閲覧専用",
|
43 |
-
'ko': "읽기 전용",
|
44 |
'fr': "Pour consultation seulement",
|
45 |
'es': "Solo para visualización",
|
46 |
-
'sv': "Endast för visning",
|
47 |
-
};
|
48 |
-
|
49 |
-
var deleteConfirm_i18n_pref = {
|
50 |
-
'zh': "你真的要删除 ",
|
51 |
-
'en': "Are you sure you want to delete ",
|
52 |
-
'ja': "本当に ",
|
53 |
-
'ko': "정말로 ",
|
54 |
-
'sv': "Är du säker på att du vill ta bort "
|
55 |
-
};
|
56 |
-
var deleteConfirm_i18n_suff = {
|
57 |
-
'zh': " 吗?",
|
58 |
-
'en': " ?",
|
59 |
-
'ja': " を削除してもよろしいですか?",
|
60 |
-
'ko': " 을(를) 삭제하시겠습니까?",
|
61 |
-
'sv': " ?"
|
62 |
-
};
|
63 |
-
var deleteConfirm_msg_pref = "Are you sure you want to delete ";
|
64 |
-
var deleteConfirm_msg_suff = " ?";
|
65 |
-
|
66 |
-
var usingLatest_i18n = {
|
67 |
-
'zh': "您使用的就是最新版!",
|
68 |
-
'en': "You are using the latest version!",
|
69 |
-
'ja': "最新バージョンを使用しています!",
|
70 |
-
'ko': "최신 버전을 사용하고 있습니다!",
|
71 |
-
'sv': "Du använder den senaste versionen!"
|
72 |
};
|
73 |
|
74 |
// gradio 页面加载好了么??? 我能动你的元素了么??
|
@@ -81,12 +47,9 @@ function gradioLoaded(mutations) {
|
|
81 |
userInfoDiv = document.getElementById("user_info");
|
82 |
appTitleDiv = document.getElementById("app_title");
|
83 |
chatbot = document.querySelector('#chuanhu_chatbot');
|
84 |
-
chatbotWrap = document.querySelector('#chuanhu_chatbot > .
|
85 |
apSwitch = document.querySelector('.apSwitch input[type="checkbox"]');
|
86 |
-
|
87 |
-
sendBtn = document.getElementById("submit_btn");
|
88 |
-
cancelBtn = document.getElementById("cancel_btn");
|
89 |
-
sliders = document.querySelectorAll('input[type="range"]');
|
90 |
|
91 |
if (loginUserForm) {
|
92 |
localStorage.setItem("userLogged", true);
|
@@ -113,54 +76,29 @@ function gradioLoaded(mutations) {
|
|
113 |
loadHistoryHtml();
|
114 |
}
|
115 |
setChatbotScroll();
|
116 |
-
mObserver.observe(chatbotWrap, { attributes: true, childList: true, subtree: true, characterData: true});
|
117 |
-
}
|
118 |
-
if (sliders) {
|
119 |
-
setSlider();
|
120 |
}
|
121 |
-
if (
|
122 |
-
|
123 |
-
const longTimeNoCheck = currentTime - lastCheckTime > 3 * 24 * 60 * 60 * 1000;
|
124 |
-
if (longTimeNoCheck && !updateInfoGotten && !isLatestVersion || isLatestVersion && !updateInfoGotten) {
|
125 |
-
updateLatestVersion();
|
126 |
-
}
|
127 |
-
}
|
128 |
-
if (cancelBtn) {
|
129 |
-
submitObserver.observe(cancelBtn, { attributes: true, characterData: true});
|
130 |
}
|
131 |
}
|
132 |
}
|
133 |
}
|
134 |
|
135 |
function webLocale() {
|
136 |
-
|
137 |
if (forView_i18n.hasOwnProperty(language)) {
|
138 |
var forView = forView_i18n[language];
|
139 |
var forViewStyle = document.createElement('style');
|
140 |
-
forViewStyle.innerHTML = '.
|
141 |
document.head.appendChild(forViewStyle);
|
142 |
-
|
143 |
-
if (deleteConfirm_i18n_pref.hasOwnProperty(language)) {
|
144 |
-
deleteConfirm_msg_pref = deleteConfirm_i18n_pref[language];
|
145 |
-
deleteConfirm_msg_suff = deleteConfirm_i18n_suff[language];
|
146 |
}
|
147 |
}
|
148 |
|
149 |
-
function showConfirmationDialog(a, file, c) {
|
150 |
-
if (file != "") {
|
151 |
-
var result = confirm(deleteConfirm_msg_pref + file + deleteConfirm_msg_suff);
|
152 |
-
if (result) {
|
153 |
-
return [a, file, c];
|
154 |
-
}
|
155 |
-
}
|
156 |
-
return [a, "CANCELED", c];
|
157 |
-
}
|
158 |
-
|
159 |
function selectHistory() {
|
160 |
user_input_ta = user_input_tb.querySelector("textarea");
|
161 |
if (user_input_ta) {
|
162 |
observer.disconnect(); // 停止监听
|
163 |
-
disableSendBtn();
|
164 |
// 在 textarea 上监听 keydown 事件
|
165 |
user_input_ta.addEventListener("keydown", function (event) {
|
166 |
var value = user_input_ta.value.trim();
|
@@ -205,13 +143,6 @@ function selectHistory() {
|
|
205 |
}
|
206 |
}
|
207 |
|
208 |
-
function disableSendBtn() {
|
209 |
-
sendBtn.disabled = user_input_ta.value.trim() === '';
|
210 |
-
user_input_ta.addEventListener('input', () => {
|
211 |
-
sendBtn.disabled = user_input_ta.value.trim() === '';
|
212 |
-
});
|
213 |
-
}
|
214 |
-
|
215 |
var username = null;
|
216 |
function getUserInfo() {
|
217 |
if (usernameGotten) {
|
@@ -250,6 +181,8 @@ function toggleUserInfoVisibility(shouldHide) {
|
|
250 |
}
|
251 |
}
|
252 |
function showOrHideUserInfo() {
|
|
|
|
|
253 |
// Bind mouse/touch events to show/hide user info
|
254 |
appTitleDiv.addEventListener("mouseenter", function () {
|
255 |
toggleUserInfoVisibility(false);
|
@@ -333,21 +266,22 @@ function setChatbotHeight() {
|
|
333 |
const screenWidth = window.innerWidth;
|
334 |
const statusDisplay = document.querySelector('#status_display');
|
335 |
const statusDisplayHeight = statusDisplay ? statusDisplay.offsetHeight : 0;
|
|
|
336 |
const vh = window.innerHeight * 0.01;
|
337 |
document.documentElement.style.setProperty('--vh', `${vh}px`);
|
338 |
if (isInIframe) {
|
339 |
chatbot.style.height = `700px`;
|
340 |
-
|
341 |
} else {
|
342 |
if (screenWidth <= 320) {
|
343 |
chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 150}px)`;
|
344 |
-
|
345 |
} else if (screenWidth <= 499) {
|
346 |
chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 100}px)`;
|
347 |
-
|
348 |
} else {
|
349 |
chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 160}px)`;
|
350 |
-
|
351 |
}
|
352 |
}
|
353 |
}
|
@@ -387,12 +321,12 @@ function addChuanhuButton(botElement) {
|
|
387 |
}
|
388 |
return;
|
389 |
}
|
390 |
-
var
|
391 |
-
var
|
392 |
-
|
393 |
-
|
394 |
-
if (
|
395 |
-
if (
|
396 |
|
397 |
// Copy bot button
|
398 |
var copyButton = document.createElement('button');
|
@@ -400,34 +334,19 @@ function addChuanhuButton(botElement) {
|
|
400 |
copyButton.classList.add('copy-bot-btn');
|
401 |
copyButton.setAttribute('aria-label', 'Copy');
|
402 |
copyButton.innerHTML = copyIcon;
|
403 |
-
copyButton.addEventListener('click',
|
404 |
const textToCopy = rawMessage.innerText;
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
copyButton.innerHTML = copiedIcon;
|
409 |
setTimeout(() => {
|
410 |
copyButton.innerHTML = copyIcon;
|
411 |
}, 1500);
|
412 |
-
}
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
textArea.select();
|
417 |
-
try {
|
418 |
-
document.execCommand('copy');
|
419 |
-
copyButton.innerHTML = copiedIcon;
|
420 |
-
setTimeout(() => {
|
421 |
-
copyButton.innerHTML = copyIcon;
|
422 |
-
}, 1500);
|
423 |
-
} catch (error) {
|
424 |
-
console.error("Copy failed: ", error);
|
425 |
-
}
|
426 |
-
document.body.removeChild(textArea);
|
427 |
-
}
|
428 |
-
} catch (error) {
|
429 |
-
console.error("Copy failed: ", error);
|
430 |
-
}
|
431 |
});
|
432 |
botElement.appendChild(copyButton);
|
433 |
|
@@ -467,48 +386,44 @@ function removeMarkdownText(message) {
|
|
467 |
let timeoutId;
|
468 |
let isThrottled = false;
|
469 |
var mmutation
|
470 |
-
//
|
471 |
var mObserver = new MutationObserver(function (mutationsList) {
|
472 |
for (mmutation of mutationsList) {
|
473 |
if (mmutation.type === 'childList') {
|
474 |
for (var node of mmutation.addedNodes) {
|
475 |
-
if (node.nodeType === 1 && node.classList.contains('message')) {
|
476 |
saveHistoryHtml();
|
477 |
-
|
478 |
-
|
|
|
|
|
479 |
}
|
480 |
}
|
481 |
for (var node of mmutation.removedNodes) {
|
482 |
-
if (node.nodeType === 1 && node.classList.contains('message')) {
|
483 |
saveHistoryHtml();
|
484 |
-
|
485 |
-
document.querySelectorAll('#chuanhu_chatbot .message-wrap .message.bot').forEach(addChuanhuButton);
|
486 |
}
|
487 |
}
|
488 |
} else if (mmutation.type === 'attributes') {
|
489 |
-
if (
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
|
|
498 |
}
|
499 |
}
|
500 |
});
|
501 |
-
|
502 |
-
|
503 |
-
var submitObserver = new MutationObserver(function (mutationsList) {
|
504 |
-
document.querySelectorAll('#chuanhu_chatbot .message-wrap .message.bot').forEach(addChuanhuButton);
|
505 |
-
saveHistoryHtml();
|
506 |
-
});
|
507 |
|
508 |
var loadhistorytime = 0; // for debugging
|
509 |
function saveHistoryHtml() {
|
510 |
-
var historyHtml = document.querySelector('#chuanhu_chatbot
|
511 |
-
if (!historyHtml) return; // no history, do nothing
|
512 |
localStorage.setItem('chatHistory', historyHtml.innerHTML);
|
513 |
// console.log("History Saved")
|
514 |
historyLoaded = false;
|
@@ -559,98 +474,12 @@ function clearHistoryHtml() {
|
|
559 |
console.log("History Cleared");
|
560 |
}
|
561 |
}
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
const response = await fetch('https://api.github.com/repos/gaizhenbiao/chuanhuchatgpt/releases/latest');
|
567 |
-
if (!response.ok) {
|
568 |
-
console.log(`Error: ${response.status} - ${response.statusText}`);
|
569 |
-
updateInfoGotten = true;
|
570 |
-
return null;
|
571 |
-
}
|
572 |
-
const data = await response.json();
|
573 |
-
updateInfoGotten = true;
|
574 |
-
return data;
|
575 |
-
} catch (error) {
|
576 |
-
console.log(`Error: ${error}`);
|
577 |
-
updateInfoGotten = true;
|
578 |
-
return null;
|
579 |
-
}
|
580 |
-
}
|
581 |
-
async function updateLatestVersion() {
|
582 |
-
const currentVersionElement = document.getElementById('current-version');
|
583 |
-
const latestVersionElement = document.getElementById('latest-version-title');
|
584 |
-
const releaseNoteElement = document.getElementById('release-note-content');
|
585 |
-
const currentVersion = currentVersionElement.textContent;
|
586 |
-
const versionTime = document.getElementById('version-time').innerText;
|
587 |
-
const localVersionTime = versionTime !== "unknown" ? (new Date(versionTime)).getTime() : 0;
|
588 |
-
updateInfoGotten = true; //无论成功与否都只执行一次,否则容易api超限...
|
589 |
-
try {
|
590 |
-
const data = await getLatestRelease();
|
591 |
-
const releaseNote = data.body;
|
592 |
-
if (releaseNote) {
|
593 |
-
releaseNoteElement.innerHTML = marked.parse(releaseNote, {mangle: false, headerIds: false});
|
594 |
-
}
|
595 |
-
const latestVersion = data.tag_name;
|
596 |
-
const latestVersionTime = (new Date(data.created_at)).getTime();
|
597 |
-
if (latestVersionTime) {
|
598 |
-
if (localVersionTime < latestVersionTime) {
|
599 |
-
latestVersionElement.textContent = latestVersion;
|
600 |
-
console.log(`New version ${latestVersion} found!`);
|
601 |
-
if (!isInIframe) {openUpdateToast();}
|
602 |
-
} else {
|
603 |
-
noUpdate();
|
604 |
-
}
|
605 |
-
currentTime = new Date().getTime();
|
606 |
-
localStorage.setItem('lastCheckTime', currentTime);
|
607 |
-
}
|
608 |
-
} catch (error) {
|
609 |
-
console.error(error);
|
610 |
-
}
|
611 |
-
}
|
612 |
-
function getUpdate() {
|
613 |
-
window.open('https://github.com/gaizhenbiao/chuanhuchatgpt/releases/latest', '_blank');
|
614 |
-
closeUpdateToast();
|
615 |
-
}
|
616 |
-
function cancelUpdate() {
|
617 |
-
closeUpdateToast();
|
618 |
-
}
|
619 |
-
function openUpdateToast() {
|
620 |
-
showingUpdateInfo = true;
|
621 |
-
setUpdateWindowHeight();
|
622 |
-
}
|
623 |
-
function closeUpdateToast() {
|
624 |
-
updateToast.style.setProperty('top', '-500px');
|
625 |
-
showingUpdateInfo = false;
|
626 |
-
}
|
627 |
-
function manualCheckUpdate() {
|
628 |
-
openUpdateToast();
|
629 |
-
updateLatestVersion();
|
630 |
-
currentTime = new Date().getTime();
|
631 |
-
localStorage.setItem('lastCheckTime', currentTime);
|
632 |
}
|
633 |
-
function noUpdate() {
|
634 |
-
localStorage.setItem('isLatestVersion', 'true');
|
635 |
-
isLatestVersion = true;
|
636 |
-
const versionInfoElement = document.getElementById('version-info-title');
|
637 |
-
const releaseNoteWrap = document.getElementById('release-note-wrap');
|
638 |
-
const gotoUpdateBtn = document.getElementById('goto-update-btn');
|
639 |
-
const closeUpdateBtn = document.getElementById('close-update-btn');
|
640 |
|
641 |
-
versionInfoElement.textContent = usingLatest_i18n.hasOwnProperty(language) ? usingLatest_i18n[language] : usingLatest_i18n['en'];
|
642 |
-
releaseNoteWrap.style.setProperty('display', 'none');
|
643 |
-
gotoUpdateBtn.classList.add('hideK');
|
644 |
-
closeUpdateBtn.classList.remove('hideK');
|
645 |
-
}
|
646 |
-
function setUpdateWindowHeight() {
|
647 |
-
if (!showingUpdateInfo) {return;}
|
648 |
-
const scrollPosition = window.scrollY;
|
649 |
-
// const originalTop = updateToast.style.getPropertyValue('top');
|
650 |
-
const resultTop = scrollPosition - 20 + 'px';
|
651 |
-
updateToast.style.setProperty('top', resultTop);
|
652 |
-
}
|
653 |
-
|
654 |
// 监视页面内部 DOM 变动
|
655 |
var observer = new MutationObserver(function (mutations) {
|
656 |
gradioLoaded(mutations);
|
@@ -663,43 +492,9 @@ window.addEventListener("DOMContentLoaded", function () {
|
|
663 |
historyLoaded = false;
|
664 |
});
|
665 |
window.addEventListener('resize', setChatbotHeight);
|
666 |
-
window.addEventListener('scroll',
|
667 |
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", adjustDarkMode);
|
668 |
|
669 |
-
// console suprise
|
670 |
-
var styleTitle1 = `
|
671 |
-
font-size: 16px;
|
672 |
-
font-family: ui-monospace, monospace;
|
673 |
-
color: #06AE56;
|
674 |
-
`
|
675 |
-
var styleDesc1 = `
|
676 |
-
font-size: 12px;
|
677 |
-
font-family: ui-monospace, monospace;
|
678 |
-
`
|
679 |
-
function makeML(str) {
|
680 |
-
let l = new String(str)
|
681 |
-
l = l.substring(l.indexOf("/*") + 3, l.lastIndexOf("*/"))
|
682 |
-
return l
|
683 |
-
}
|
684 |
-
let ChuanhuInfo = function () {
|
685 |
-
/*
|
686 |
-
________ __ ________ __
|
687 |
-
/ ____/ /_ __ ______ _____ / /_ __ __ / ____/ /_ ____ _/ /_
|
688 |
-
/ / / __ \/ / / / __ `/ __ \/ __ \/ / / / / / / __ \/ __ `/ __/
|
689 |
-
/ /___/ / / / /_/ / /_/ / / / / / / / /_/ / / /___/ / / / /_/ / /_
|
690 |
-
\____/_/ /_/\__,_/\__,_/_/ /_/_/ /_/\__,_/ \____/_/ /_/\__,_/\__/
|
691 |
-
|
692 |
-
川虎Chat (Chuanhu Chat) - GUI for ChatGPT API and many LLMs
|
693 |
-
*/
|
694 |
-
}
|
695 |
-
let description = `
|
696 |
-
© 2023 Chuanhu, MZhao, Keldos
|
697 |
-
GitHub repository: [https://github.com/GaiZhenbiao/ChuanhuChatGPT]\n
|
698 |
-
Enjoy our project!\n
|
699 |
-
`
|
700 |
-
console.log(`%c${makeML(ChuanhuInfo)}`,styleTitle1)
|
701 |
-
console.log(`%c${description}`, styleDesc1)
|
702 |
-
|
703 |
// button svg code
|
704 |
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>';
|
705 |
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>';
|
|
|
15 |
var chatbot = null;
|
16 |
var chatbotWrap = null;
|
17 |
var apSwitch = null;
|
18 |
+
var empty_botton = null;
|
19 |
var messageBotDivs = null;
|
20 |
var loginUserForm = null;
|
21 |
var logginUser = null;
|
|
|
|
|
|
|
|
|
22 |
|
23 |
var userLogged = false;
|
24 |
var usernameGotten = false;
|
25 |
var historyLoaded = false;
|
|
|
|
|
26 |
|
27 |
var ga = document.getElementsByTagName("gradio-app");
|
28 |
var targetNode = ga[0];
|
29 |
var isInIframe = (window.self !== window.top);
|
30 |
var language = navigator.language.slice(0,2);
|
|
|
31 |
|
|
|
32 |
var forView_i18n = {
|
33 |
'zh': "仅供查看",
|
34 |
'en': "For viewing only",
|
35 |
'ja': "閲覧専用",
|
|
|
36 |
'fr': "Pour consultation seulement",
|
37 |
'es': "Solo para visualización",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
};
|
39 |
|
40 |
// gradio 页面加载好了么??? 我能动你的元素了么??
|
|
|
47 |
userInfoDiv = document.getElementById("user_info");
|
48 |
appTitleDiv = document.getElementById("app_title");
|
49 |
chatbot = document.querySelector('#chuanhu_chatbot');
|
50 |
+
chatbotWrap = document.querySelector('#chuanhu_chatbot > .wrap');
|
51 |
apSwitch = document.querySelector('.apSwitch input[type="checkbox"]');
|
52 |
+
empty_botton = document.getElementById("empty_btn")
|
|
|
|
|
|
|
53 |
|
54 |
if (loginUserForm) {
|
55 |
localStorage.setItem("userLogged", true);
|
|
|
76 |
loadHistoryHtml();
|
77 |
}
|
78 |
setChatbotScroll();
|
|
|
|
|
|
|
|
|
79 |
}
|
80 |
+
if (empty_botton) {
|
81 |
+
emptyHistory();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
}
|
83 |
}
|
84 |
}
|
85 |
}
|
86 |
|
87 |
function webLocale() {
|
88 |
+
console.log("webLocale", language);
|
89 |
if (forView_i18n.hasOwnProperty(language)) {
|
90 |
var forView = forView_i18n[language];
|
91 |
var forViewStyle = document.createElement('style');
|
92 |
+
forViewStyle.innerHTML = '.wrap>.history-message>:last-child::after { content: "' + forView + '"!important; }';
|
93 |
document.head.appendChild(forViewStyle);
|
94 |
+
// console.log("added forViewStyle", forView);
|
|
|
|
|
|
|
95 |
}
|
96 |
}
|
97 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
function selectHistory() {
|
99 |
user_input_ta = user_input_tb.querySelector("textarea");
|
100 |
if (user_input_ta) {
|
101 |
observer.disconnect(); // 停止监听
|
|
|
102 |
// 在 textarea 上监听 keydown 事件
|
103 |
user_input_ta.addEventListener("keydown", function (event) {
|
104 |
var value = user_input_ta.value.trim();
|
|
|
143 |
}
|
144 |
}
|
145 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
var username = null;
|
147 |
function getUserInfo() {
|
148 |
if (usernameGotten) {
|
|
|
181 |
}
|
182 |
}
|
183 |
function showOrHideUserInfo() {
|
184 |
+
var sendBtn = document.getElementById("submit_btn");
|
185 |
+
|
186 |
// Bind mouse/touch events to show/hide user info
|
187 |
appTitleDiv.addEventListener("mouseenter", function () {
|
188 |
toggleUserInfoVisibility(false);
|
|
|
266 |
const screenWidth = window.innerWidth;
|
267 |
const statusDisplay = document.querySelector('#status_display');
|
268 |
const statusDisplayHeight = statusDisplay ? statusDisplay.offsetHeight : 0;
|
269 |
+
const wrap = chatbot.querySelector('.wrap');
|
270 |
const vh = window.innerHeight * 0.01;
|
271 |
document.documentElement.style.setProperty('--vh', `${vh}px`);
|
272 |
if (isInIframe) {
|
273 |
chatbot.style.height = `700px`;
|
274 |
+
wrap.style.maxHeight = `calc(700px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`
|
275 |
} else {
|
276 |
if (screenWidth <= 320) {
|
277 |
chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 150}px)`;
|
278 |
+
wrap.style.maxHeight = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 150}px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`;
|
279 |
} else if (screenWidth <= 499) {
|
280 |
chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 100}px)`;
|
281 |
+
wrap.style.maxHeight = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 100}px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`;
|
282 |
} else {
|
283 |
chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 160}px)`;
|
284 |
+
wrap.style.maxHeight = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 160}px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`;
|
285 |
}
|
286 |
}
|
287 |
}
|
|
|
321 |
}
|
322 |
return;
|
323 |
}
|
324 |
+
var copyButton = null;
|
325 |
+
var toggleButton = null;
|
326 |
+
copyButton = botElement.querySelector('button.copy-bot-btn');
|
327 |
+
toggleButton = botElement.querySelector('button.toggle-md-btn');
|
328 |
+
if (copyButton) copyButton.remove();
|
329 |
+
if (toggleButton) toggleButton.remove();
|
330 |
|
331 |
// Copy bot button
|
332 |
var copyButton = document.createElement('button');
|
|
|
334 |
copyButton.classList.add('copy-bot-btn');
|
335 |
copyButton.setAttribute('aria-label', 'Copy');
|
336 |
copyButton.innerHTML = copyIcon;
|
337 |
+
copyButton.addEventListener('click', () => {
|
338 |
const textToCopy = rawMessage.innerText;
|
339 |
+
navigator.clipboard
|
340 |
+
.writeText(textToCopy)
|
341 |
+
.then(() => {
|
342 |
copyButton.innerHTML = copiedIcon;
|
343 |
setTimeout(() => {
|
344 |
copyButton.innerHTML = copyIcon;
|
345 |
}, 1500);
|
346 |
+
})
|
347 |
+
.catch(() => {
|
348 |
+
console.error("copy failed");
|
349 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
350 |
});
|
351 |
botElement.appendChild(copyButton);
|
352 |
|
|
|
386 |
let timeoutId;
|
387 |
let isThrottled = false;
|
388 |
var mmutation
|
389 |
+
// 监听所有元素中 bot message 的变化,为 bot 消息添加复制按钮。
|
390 |
var mObserver = new MutationObserver(function (mutationsList) {
|
391 |
for (mmutation of mutationsList) {
|
392 |
if (mmutation.type === 'childList') {
|
393 |
for (var node of mmutation.addedNodes) {
|
394 |
+
if (node.nodeType === 1 && node.classList.contains('message') && node.getAttribute('data-testid') === 'bot') {
|
395 |
saveHistoryHtml();
|
396 |
+
document.querySelectorAll('#chuanhu_chatbot>.wrap>.message-wrap .message.bot').forEach(addChuanhuButton);
|
397 |
+
}
|
398 |
+
if (node.tagName === 'INPUT' && node.getAttribute('type') === 'range') {
|
399 |
+
setSlider();
|
400 |
}
|
401 |
}
|
402 |
for (var node of mmutation.removedNodes) {
|
403 |
+
if (node.nodeType === 1 && node.classList.contains('message') && node.getAttribute('data-testid') === 'bot') {
|
404 |
saveHistoryHtml();
|
405 |
+
document.querySelectorAll('#chuanhu_chatbot>.wrap>.message-wrap .message.bot').forEach(addChuanhuButton);
|
|
|
406 |
}
|
407 |
}
|
408 |
} else if (mmutation.type === 'attributes') {
|
409 |
+
if (mmutation.target.nodeType === 1 && mmutation.target.classList.contains('message') && mmutation.target.getAttribute('data-testid') === 'bot') {
|
410 |
+
if (isThrottled) break; // 为了防止重复不断疯狂渲染,加上等待_(:з」∠)_
|
411 |
+
isThrottled = true;
|
412 |
+
clearTimeout(timeoutId);
|
413 |
+
timeoutId = setTimeout(() => {
|
414 |
+
isThrottled = false;
|
415 |
+
document.querySelectorAll('#chuanhu_chatbot>.wrap>.message-wrap .message.bot').forEach(addChuanhuButton);
|
416 |
+
saveHistoryHtml();
|
417 |
+
}, 500);
|
418 |
+
}
|
419 |
}
|
420 |
}
|
421 |
});
|
422 |
+
mObserver.observe(document.documentElement, { attributes: true, childList: true, subtree: true });
|
|
|
|
|
|
|
|
|
|
|
423 |
|
424 |
var loadhistorytime = 0; // for debugging
|
425 |
function saveHistoryHtml() {
|
426 |
+
var historyHtml = document.querySelector('#chuanhu_chatbot > .wrap');
|
|
|
427 |
localStorage.setItem('chatHistory', historyHtml.innerHTML);
|
428 |
// console.log("History Saved")
|
429 |
historyLoaded = false;
|
|
|
474 |
console.log("History Cleared");
|
475 |
}
|
476 |
}
|
477 |
+
function emptyHistory() {
|
478 |
+
empty_botton.addEventListener("click", function () {
|
479 |
+
clearHistoryHtml();
|
480 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
481 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
482 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
483 |
// 监视页面内部 DOM 变动
|
484 |
var observer = new MutationObserver(function (mutations) {
|
485 |
gradioLoaded(mutations);
|
|
|
492 |
historyLoaded = false;
|
493 |
});
|
494 |
window.addEventListener('resize', setChatbotHeight);
|
495 |
+
window.addEventListener('scroll', setChatbotHeight);
|
496 |
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", adjustDarkMode);
|
497 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
498 |
// button svg code
|
499 |
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>';
|
500 |
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>';
|
assets/favicon.ico
CHANGED
assets/favicon.png
ADDED
assets/html/appearance_switcher.html
CHANGED
@@ -1,6 +1,11 @@
|
|
1 |
-
<div
|
2 |
-
<
|
3 |
-
|
4 |
-
|
5 |
-
|
|
|
|
|
|
|
|
|
|
|
6 |
</div>
|
|
|
1 |
+
<div style="display: flex; justify-content: space-between;">
|
2 |
+
<span style="margin-top: 4px !important;">
|
3 |
+
{label}
|
4 |
+
</span>
|
5 |
+
<span>
|
6 |
+
<label class="apSwitch" for="checkbox">
|
7 |
+
<input type="checkbox" id="checkbox">
|
8 |
+
<div class="apSlider"></div>
|
9 |
+
</label>
|
10 |
+
</span>
|
11 |
</div>
|
assets/html/billing_info.html
DELETED
@@ -1,9 +0,0 @@
|
|
1 |
-
<b>{label}</b>
|
2 |
-
<div class="progress-bar">
|
3 |
-
<div class="progress" style="width: {usage_percent}%;">
|
4 |
-
<span class="progress-text">{usage_percent}%</span>
|
5 |
-
</div>
|
6 |
-
</div>
|
7 |
-
<div style="display: flex; justify-content: space-between;">
|
8 |
-
<span>${rounded_usage}</span><span>${usage_limit}</span>
|
9 |
-
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assets/html/update.html
DELETED
@@ -1,25 +0,0 @@
|
|
1 |
-
<div id="toast-update">
|
2 |
-
<div id="check-chuanhu-update">
|
3 |
-
<p style="display:none">
|
4 |
-
<span id="current-version">{current_version}</span>
|
5 |
-
<span id="version-time">{version_time}</span>
|
6 |
-
</p>
|
7 |
-
<p id="version-info-title">
|
8 |
-
Latest Version: <a href="https://github.com/gaizhenbiao/chuanhuchatgpt/releases/latest" target="_blank"
|
9 |
-
id="latest-version-title" style="text-decoration: none;">getting latest version...</a>
|
10 |
-
</p>
|
11 |
-
<div id="release-note-wrap">
|
12 |
-
<div class="release-note-content" id="release-note-content">
|
13 |
-
Getting Release Note...
|
14 |
-
</div>
|
15 |
-
</div>
|
16 |
-
<div id="goto-update-btn" class="btn-update-group">
|
17 |
-
<button class="btn-update lg secondary svelte-1ipelgc" id="cancel-button" onclick="cancelUpdate()">{cancel_btn}</button>
|
18 |
-
<button class="btn-update lg primary svelte-1ipelgc" id="update-button" onclick="getUpdate()">{update_btn}</button>
|
19 |
-
</div>
|
20 |
-
<div id="close-update-btn" class="btn-update-group hideK">
|
21 |
-
<button class="btn-update lg secondary svelte-1jrzxu" id="update-button" onclick="getUpdate()">{seenew_btn}</button>
|
22 |
-
<button class="btn-update lg primary svelte-1jrzxu" id="cancel-button" onclick="cancelUpdate()">{ok_btn}</button>
|
23 |
-
</div>
|
24 |
-
</div>
|
25 |
-
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
chatgpt - macOS.command
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
echo Opening ChuanhuChatGPT...
|
3 |
+
cd "$(dirname "${BASH_SOURCE[0]}")"
|
4 |
+
nohup python3 ChuanhuChatbot.py >/dev/null 2>&1 &
|
5 |
+
sleep 5
|
6 |
+
open http://127.0.0.1:7860
|
7 |
+
echo Finished opening ChuanhuChatGPT (http://127.0.0.1:7860/). If you kill ChuanhuChatbot, Use "pkill -f 'ChuanhuChatbot'" command in terminal.
|
chatgpt - windows.bat
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@echo off
|
2 |
+
echo Opening ChuanhuChatGPT...
|
3 |
+
|
4 |
+
REM Open powershell via bat
|
5 |
+
start powershell.exe -NoExit -Command "python ./ChuanhuChatbot.py"
|
6 |
+
|
7 |
+
REM The web page can be accessed with delayed start http://127.0.0.1:7860/
|
8 |
+
ping -n 5 127.0.0.1>nul
|
9 |
+
|
10 |
+
REM access chargpt via your default browser
|
11 |
+
start "" "http://127.0.0.1:7860/"
|
12 |
+
|
13 |
+
|
14 |
+
echo Finished opening ChuanhuChatGPT (http://127.0.0.1:7860/).
|
config.json
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"hide_history_when_not_logged_in": true
|
3 |
+
}
|
config_example.json
CHANGED
@@ -1,53 +1,24 @@
|
|
1 |
{
|
2 |
-
//
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
"
|
7 |
-
"
|
8 |
-
|
9 |
-
"
|
10 |
-
|
11 |
-
//== Azure ==
|
12 |
-
"openai_api_type": "openai", // 可选项:azure, openai
|
13 |
-
"azure_openai_api_key": "", // 你的 Azure OpenAI API Key,用于 Azure OpenAI 对话模型
|
14 |
-
"azure_openai_api_base_url": "", // 你的 Azure Base URL
|
15 |
-
"azure_openai_api_version": "2023-05-15", // 你的 Azure OpenAI API 版本
|
16 |
-
"azure_deployment_name": "", // 你的 Azure OpenAI Chat 模型 Deployment 名称
|
17 |
-
"azure_embedding_deployment_name": "", // 你的 Azure OpenAI Embedding 模型 Deployment 名称
|
18 |
-
"azure_embedding_model_name": "text-embedding-ada-002", // 你的 Azure OpenAI Embedding 模型名称
|
19 |
-
|
20 |
-
//== 基础配置 ==
|
21 |
-
"language": "auto", // 界面语言,可选"auto", "zh-CN", "en-US", "ja-JP", "ko-KR", "sv-SE"
|
22 |
"users": [], // 用户列表,[[用户名1, 密码1], [用户名2, 密码2], ...]
|
23 |
"local_embedding": false, //是否在本地编制索引
|
24 |
-
"hide_history_when_not_logged_in": false, //未登录情况下是否不展示对话历史
|
25 |
-
"check_update": true, //是否启用检查更新
|
26 |
"default_model": "gpt-3.5-turbo", // 默认模型
|
27 |
-
|
28 |
-
//== API 用量 ==
|
29 |
-
"show_api_billing": false, //是否显示OpenAI API用量(启用需要填写sensitive_id)
|
30 |
-
"sensitive_id": "", // 你 OpenAI 账户的 Sensitive ID,用于查询 API 用量
|
31 |
-
"usage_limit": 120, // 该 OpenAI API Key 的当月限额,单位:美元,用于计算百分比和显示上限
|
32 |
-
"legacy_api_usage": false, // 是否使用旧版 API 用量查询接口(OpenAI现已关闭该接口,但是如果你在使用第三方 API,第三方可能仍然支持此接口)
|
33 |
-
|
34 |
-
//== 川虎助理设置 ==
|
35 |
-
"default_chuanhu_assistant_model": "gpt-4", //川虎助理使用的模型,可选gpt-3.5-turbo或者gpt-4等
|
36 |
-
"GOOGLE_CSE_ID": "", //谷歌搜索引擎ID,用于川虎助理Pro模式,获取方式请看 https://stackoverflow.com/questions/37083058/programmatically-searching-google-in-python-using-custom-search
|
37 |
-
"GOOGLE_API_KEY": "", //谷歌API Key,用于川虎助理Pro模式
|
38 |
-
"WOLFRAM_ALPHA_APPID": "", //Wolfram Alpha API Key,用于川虎助理Pro模式,获取方式请看 https://products.wolframalpha.com/api/
|
39 |
-
"SERPAPI_API_KEY": "", //SerpAPI API Key,用于川虎助理Pro模式,获取方式请看 https://serpapi.com/
|
40 |
-
|
41 |
-
//== 文档处理与显示 ==
|
42 |
-
"latex_option": "default", // LaTeX 公式渲染策略,可选"default", "strict", "all"或者"disabled"
|
43 |
"advance_docs": {
|
44 |
"pdf": {
|
45 |
-
|
46 |
-
"
|
|
|
|
|
47 |
}
|
48 |
},
|
49 |
-
|
50 |
-
//== 高级配置 ==
|
51 |
// 是否多个API Key轮换使用
|
52 |
"multi_api_key": false,
|
53 |
"api_key_list": [
|
@@ -55,12 +26,7 @@
|
|
55 |
"sk-xxxxxxxxxxxxxxxxxxxxxxxx2",
|
56 |
"sk-xxxxxxxxxxxxxxxxxxxxxxxx3"
|
57 |
],
|
58 |
-
//
|
59 |
-
// "openai_api_base": "https://api.openai.com",
|
60 |
-
// 自定义使用代理(请替换代理URL)
|
61 |
-
// "https_proxy": "http://127.0.0.1:1079",
|
62 |
-
// "http_proxy": "http://127.0.0.1:1079",
|
63 |
-
// 自定义端口、自定义ip(请替换对应内容)
|
64 |
// "server_name": "0.0.0.0",
|
65 |
// "server_port": 7860,
|
66 |
// 如果要share到gradio,设置为true
|
|
|
1 |
{
|
2 |
+
// 你的OpenAI API Key,一般必填,
|
3 |
+
// 若缺省填为 "openai_api_key": "" 则必须再在图形界面中填入API Key
|
4 |
+
"openai_api_key": "",
|
5 |
+
// 你的xmchat API Key,与OpenAI API Key不同
|
6 |
+
"xmchat_api_key": "",
|
7 |
+
"language": "auto",
|
8 |
+
// 如果使用代理,请取消注释下面的两行,并替换代理URL
|
9 |
+
// "https_proxy": "http://127.0.0.1:1079",
|
10 |
+
// "http_proxy": "http://127.0.0.1:1079",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
"users": [], // 用户列表,[[用户名1, 密码1], [用户名2, 密码2], ...]
|
12 |
"local_embedding": false, //是否在本地编制索引
|
|
|
|
|
13 |
"default_model": "gpt-3.5-turbo", // 默认模型
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
"advance_docs": {
|
15 |
"pdf": {
|
16 |
+
// 是否认为PDF是双栏的
|
17 |
+
"two_column": false,
|
18 |
+
// 是否使用OCR识别PDF中的公式
|
19 |
+
"formula_ocr": true
|
20 |
}
|
21 |
},
|
|
|
|
|
22 |
// 是否多个API Key轮换使用
|
23 |
"multi_api_key": false,
|
24 |
"api_key_list": [
|
|
|
26 |
"sk-xxxxxxxxxxxxxxxxxxxxxxxx2",
|
27 |
"sk-xxxxxxxxxxxxxxxxxxxxxxxx3"
|
28 |
],
|
29 |
+
// 如果使用自定义端口、自定义ip,请取消注释并替换对应内容
|
|
|
|
|
|
|
|
|
|
|
30 |
// "server_name": "0.0.0.0",
|
31 |
// "server_port": 7860,
|
32 |
// 如果要share到gradio,设置为true
|
custom.css
ADDED
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
:root {
|
2 |
+
--chatbot-color-light: #F3F3F3;
|
3 |
+
--chatbot-color-dark: #121111;
|
4 |
+
}
|
5 |
+
|
6 |
+
/* status_display */
|
7 |
+
#status_display {
|
8 |
+
display: flex;
|
9 |
+
min-height: 2.5em;
|
10 |
+
align-items: flex-end;
|
11 |
+
justify-content: flex-end;
|
12 |
+
}
|
13 |
+
#status_display p {
|
14 |
+
font-size: .85em;
|
15 |
+
font-family: monospace;
|
16 |
+
color: var(--body-text-color-subdued);
|
17 |
+
}
|
18 |
+
|
19 |
+
#chuanhu_chatbot, #status_display {
|
20 |
+
transition: all 0.6s;
|
21 |
+
}
|
22 |
+
/* list */
|
23 |
+
ol:not(.options), ul:not(.options) {
|
24 |
+
padding-inline-start: 2em !important;
|
25 |
+
}
|
26 |
+
|
27 |
+
/* 亮色 */
|
28 |
+
#chuanhu_chatbot {
|
29 |
+
background-color: var(--chatbot-color-light) !important;
|
30 |
+
}
|
31 |
+
[data-testid = "bot"] {
|
32 |
+
background-color: #FFFFFF !important;
|
33 |
+
}
|
34 |
+
[data-testid = "user"] {
|
35 |
+
background-color: #95EC69 !important;
|
36 |
+
}
|
37 |
+
/* 对话气泡 */
|
38 |
+
[class *= "message"] {
|
39 |
+
border-radius: var(--radius-xl) !important;
|
40 |
+
border: none;
|
41 |
+
padding: var(--spacing-xl) !important;
|
42 |
+
font-size: var(--text-md) !important;
|
43 |
+
line-height: var(--line-md) !important;
|
44 |
+
min-height: calc(var(--text-md)*var(--line-md) + 2*var(--spacing-xl));
|
45 |
+
min-width: calc(var(--text-md)*var(--line-md) + 2*var(--spacing-xl));
|
46 |
+
}
|
47 |
+
[data-testid = "bot"] {
|
48 |
+
max-width: 85%;
|
49 |
+
border-bottom-left-radius: 0 !important;
|
50 |
+
}
|
51 |
+
[data-testid = "user"] {
|
52 |
+
max-width: 85%;
|
53 |
+
width: auto !important;
|
54 |
+
border-bottom-right-radius: 0 !important;
|
55 |
+
}
|
56 |
+
/* 表格 */
|
57 |
+
table {
|
58 |
+
margin: 1em 0;
|
59 |
+
border-collapse: collapse;
|
60 |
+
empty-cells: show;
|
61 |
+
}
|
62 |
+
td,th {
|
63 |
+
border: 1.2px solid var(--border-color-primary) !important;
|
64 |
+
padding: 0.2em;
|
65 |
+
}
|
66 |
+
thead {
|
67 |
+
background-color: rgba(175,184,193,0.2);
|
68 |
+
}
|
69 |
+
thead th {
|
70 |
+
padding: .5em .2em;
|
71 |
+
}
|
72 |
+
/* 行内代码 */
|
73 |
+
code {
|
74 |
+
display: inline;
|
75 |
+
white-space: break-spaces;
|
76 |
+
border-radius: 6px;
|
77 |
+
margin: 0 2px 0 2px;
|
78 |
+
padding: .2em .4em .1em .4em;
|
79 |
+
background-color: rgba(175,184,193,0.2);
|
80 |
+
}
|
81 |
+
/* 代码块 */
|
82 |
+
pre code {
|
83 |
+
display: block;
|
84 |
+
overflow: auto;
|
85 |
+
white-space: pre;
|
86 |
+
background-color: hsla(0, 0%, 0%, 80%)!important;
|
87 |
+
border-radius: 10px;
|
88 |
+
padding: 1.4em 1.2em 0em 1.4em;
|
89 |
+
margin: 1.2em 2em 1.2em 0.5em;
|
90 |
+
color: #FFF;
|
91 |
+
box-shadow: 6px 6px 16px hsla(0, 0%, 0%, 0.2);
|
92 |
+
}
|
93 |
+
/* 代码高亮样式 */
|
94 |
+
.highlight .hll { background-color: #49483e }
|
95 |
+
.highlight .c { color: #75715e } /* Comment */
|
96 |
+
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
|
97 |
+
.highlight .k { color: #66d9ef } /* Keyword */
|
98 |
+
.highlight .l { color: #ae81ff } /* Literal */
|
99 |
+
.highlight .n { color: #f8f8f2 } /* Name */
|
100 |
+
.highlight .o { color: #f92672 } /* Operator */
|
101 |
+
.highlight .p { color: #f8f8f2 } /* Punctuation */
|
102 |
+
.highlight .ch { color: #75715e } /* Comment.Hashbang */
|
103 |
+
.highlight .cm { color: #75715e } /* Comment.Multiline */
|
104 |
+
.highlight .cp { color: #75715e } /* Comment.Preproc */
|
105 |
+
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
|
106 |
+
.highlight .c1 { color: #75715e } /* Comment.Single */
|
107 |
+
.highlight .cs { color: #75715e } /* Comment.Special */
|
108 |
+
.highlight .gd { color: #f92672 } /* Generic.Deleted */
|
109 |
+
.highlight .ge { font-style: italic } /* Generic.Emph */
|
110 |
+
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
|
111 |
+
.highlight .gs { font-weight: bold } /* Generic.Strong */
|
112 |
+
.highlight .gu { color: #75715e } /* Generic.Subheading */
|
113 |
+
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
|
114 |
+
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
|
115 |
+
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
|
116 |
+
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
|
117 |
+
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
|
118 |
+
.highlight .kt { color: #66d9ef } /* Keyword.Type */
|
119 |
+
.highlight .ld { color: #e6db74 } /* Literal.Date */
|
120 |
+
.highlight .m { color: #ae81ff } /* Literal.Number */
|
121 |
+
.highlight .s { color: #e6db74 } /* Literal.String */
|
122 |
+
.highlight .na { color: #a6e22e } /* Name.Attribute */
|
123 |
+
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
|
124 |
+
.highlight .nc { color: #a6e22e } /* Name.Class */
|
125 |
+
.highlight .no { color: #66d9ef } /* Name.Constant */
|
126 |
+
.highlight .nd { color: #a6e22e } /* Name.Decorator */
|
127 |
+
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
|
128 |
+
.highlight .ne { color: #a6e22e } /* Name.Exception */
|
129 |
+
.highlight .nf { color: #a6e22e } /* Name.Function */
|
130 |
+
.highlight .nl { color: #f8f8f2 } /* Name.Label */
|
131 |
+
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
|
132 |
+
.highlight .nx { color: #a6e22e } /* Name.Other */
|
133 |
+
.highlight .py { color: #f8f8f2 } /* Name.Property */
|
134 |
+
.highlight .nt { color: #f92672 } /* Name.Tag */
|
135 |
+
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
|
136 |
+
.highlight .ow { color: #f92672 } /* Operator.Word */
|
137 |
+
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
|
138 |
+
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
|
139 |
+
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
|
140 |
+
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
|
141 |
+
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
|
142 |
+
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
|
143 |
+
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
|
144 |
+
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
|
145 |
+
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
|
146 |
+
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
|
147 |
+
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
|
148 |
+
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
|
149 |
+
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
|
150 |
+
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
|
151 |
+
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
|
152 |
+
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
|
153 |
+
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
|
154 |
+
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
|
155 |
+
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
|
156 |
+
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
|
157 |
+
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
|
158 |
+
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
|
159 |
+
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
|
160 |
+
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
|
161 |
+
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
|
162 |
+
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
|
history/2023-06-14_15-05-04.json
ADDED
File without changes
|
locale/en_US.json
CHANGED
@@ -32,32 +32,24 @@
|
|
32 |
"📝 导出为Markdown": "📝 Export as Markdown",
|
33 |
"默认保存于history文件夹": "Default save in history folder",
|
34 |
"高级": "Advanced",
|
35 |
-
"# ⚠️ 务必谨慎更改
|
36 |
"参数": "Parameters",
|
37 |
-
"
|
38 |
"用于定位滥用行为": "Used to locate abuse",
|
39 |
"用户名": "Username",
|
40 |
"网络设置": "Network Settings",
|
41 |
"在这里输入API-Host...": "Type in API-Host here...",
|
42 |
"🔄 切换API地址": "🔄 Switch API Address",
|
43 |
"在这里输入代理地址...": "Type in proxy address here...",
|
44 |
-
"代理地址(示例:http://127.0.0.1:10809)": "Proxy address (example: http://127.0.0.1:10809
|
45 |
"🔄 设置代理地址": "🔄 Set Proxy Address",
|
46 |
-
"🔙
|
47 |
-
"🔄 检查更新...": "🔄 Check for Update...",
|
48 |
-
"取消": "Cancel",
|
49 |
-
"更新": "Update",
|
50 |
-
"详情": "Details",
|
51 |
-
"好": "OK",
|
52 |
"川虎Chat 🚀": "Chuanhu Chat 🚀",
|
53 |
"开始实时传输回答……": "Start streaming output...",
|
54 |
"Token 计数: ": "Token Count: ",
|
55 |
-
",本次对话累计消耗了 ": "
|
56 |
"**获取API使用情况失败**": "**Failed to get API usage**",
|
57 |
-
"**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**Failed to get API usage**, correct sensitive_id needed in `config.json`",
|
58 |
-
"**获取API使用情况失败**,sensitive_id错误或已过期": "**Failed to get API usage**, wrong or expired sensitive_id",
|
59 |
"**本月使用金额** ": "**Monthly usage** ",
|
60 |
-
"本月使用金额": "Monthly usage",
|
61 |
"获取API使用情况失败:": "Failed to get API usage:",
|
62 |
"API密钥更改为了": "The API key is changed to",
|
63 |
"JSON解析错误,收到的内容: ": "JSON parsing error, received content: ",
|
@@ -72,13 +64,10 @@
|
|
72 |
"API key为空,请检查是否输入正确。": "API key is empty, check whether it is entered correctly.",
|
73 |
"请输入对话内容。": "Enter the content of the conversation.",
|
74 |
"账单信息不适用": "Billing information is not applicable",
|
75 |
-
"由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)
|
76 |
"切换亮暗色主题": "Switch light/dark theme",
|
77 |
"您的IP区域:未知。": "Your IP region: Unknown.",
|
78 |
"获取IP地理位置失败。原因:": "Failed to get IP location. Reason: ",
|
79 |
"。你仍然可以使用聊天功能。": ". You can still use the chat function.",
|
80 |
-
"您的IP区域:": "Your IP region: "
|
81 |
-
"总结": "Summarize",
|
82 |
-
"生成内容总结中……": "Generating content summary...",
|
83 |
-
"由于下面的原因,Google 拒绝返回 PaLM 的回答:\n\n": "Due to the following reasons, Google refuses to provide an answer to PaLM: \n\n"
|
84 |
}
|
|
|
32 |
"📝 导出为Markdown": "📝 Export as Markdown",
|
33 |
"默认保存于history文件夹": "Default save in history folder",
|
34 |
"高级": "Advanced",
|
35 |
+
"# ⚠️ 务必谨慎更改 ⚠️\n\n如果无法使用请恢复默认设置": "# ⚠️ Caution: Changes require care. ⚠️\n\nIf unable to use, restore default settings.",
|
36 |
"参数": "Parameters",
|
37 |
+
"在这里输入停止符,用英文逗号隔开...": "Type in stop token here, separated by comma...",
|
38 |
"用于定位滥用行为": "Used to locate abuse",
|
39 |
"用户名": "Username",
|
40 |
"网络设置": "Network Settings",
|
41 |
"在这里输入API-Host...": "Type in API-Host here...",
|
42 |
"🔄 切换API地址": "🔄 Switch API Address",
|
43 |
"在这里输入代理地址...": "Type in proxy address here...",
|
44 |
+
"代理地址(示例:http://127.0.0.1:10809)": "Proxy address (example: http://127.0.0.1:10809)",
|
45 |
"🔄 设置代理地址": "🔄 Set Proxy Address",
|
46 |
+
"🔙 恢复默认设置": "🔙 Restore Default Settings",
|
|
|
|
|
|
|
|
|
|
|
47 |
"川虎Chat 🚀": "Chuanhu Chat 🚀",
|
48 |
"开始实时传输回答……": "Start streaming output...",
|
49 |
"Token 计数: ": "Token Count: ",
|
50 |
+
",本次对话累计消耗了 ": ",Total cost for this dialogue is ",
|
51 |
"**获取API使用情况失败**": "**Failed to get API usage**",
|
|
|
|
|
52 |
"**本月使用金额** ": "**Monthly usage** ",
|
|
|
53 |
"获取API使用情况失败:": "Failed to get API usage:",
|
54 |
"API密钥更改为了": "The API key is changed to",
|
55 |
"JSON解析错误,收到的内容: ": "JSON parsing error, received content: ",
|
|
|
64 |
"API key为空,请检查是否输入正确。": "API key is empty, check whether it is entered correctly.",
|
65 |
"请输入对话内容。": "Enter the content of the conversation.",
|
66 |
"账单信息不适用": "Billing information is not applicable",
|
67 |
+
"由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536) 和 [明昭MZhao](https://space.bilibili.com/24807452)开发<br />访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "developor: Bilibili [土川虎虎虎](https://space.bilibili.com/29125536) and [明昭MZhao](https://space.bilibili.com/24807452)\n\nDownload latest code from [GitHub](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
|
68 |
"切换亮暗色主题": "Switch light/dark theme",
|
69 |
"您的IP区域:未知。": "Your IP region: Unknown.",
|
70 |
"获取IP地理位置失败。原因:": "Failed to get IP location. Reason: ",
|
71 |
"。你仍然可以使用聊天功能。": ". You can still use the chat function.",
|
72 |
+
"您的IP区域:": "Your IP region: "
|
|
|
|
|
|
|
73 |
}
|
locale/ja_JP.json
CHANGED
@@ -32,9 +32,9 @@
|
|
32 |
"📝 导出为Markdown": "📝 Markdownでエクスポート",
|
33 |
"默认保存于history文件夹": "デフォルトでhistoryフォルダに保存されます",
|
34 |
"高级": "Advanced",
|
35 |
-
"# ⚠️ 务必谨慎更改
|
36 |
"参数": "パラメータ",
|
37 |
-
"
|
38 |
"用于定位滥用行为": "不正行為を特定するために使用されます",
|
39 |
"用户名": "ユーザー名",
|
40 |
"网络设置": "ネットワーク設定",
|
@@ -43,21 +43,13 @@
|
|
43 |
"在这里输入代理地址...": "プロキシアドレスを入力してください...",
|
44 |
"代理地址(示例:http://127.0.0.1:10809)": "プロキシアドレス(例:http://127.0.0.1:10809)",
|
45 |
"🔄 设置代理地址": "🔄 プロキシアドレスを設定",
|
46 |
-
"🔙
|
47 |
-
"🔄 检查更新...": "🔄 アップデートをチェック...",
|
48 |
-
"取消": "キャンセル",
|
49 |
-
"更新": "アップデート",
|
50 |
-
"详情": "詳細",
|
51 |
-
"好": "はい",
|
52 |
"川虎Chat 🚀": "川虎Chat 🚀",
|
53 |
"开始实时传输回答……": "ストリーム出力開始……",
|
54 |
"Token 计数: ": "Token数: ",
|
55 |
",本次对话累计消耗了 ": ", 今の会話で消費合計 ",
|
56 |
"**获取API使用情况失败**": "**API使用状況の取得に失敗しました**",
|
57 |
-
"**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**API使用状況の取得に失敗しました**、`config.json`に正しい`sensitive_id`を入力する必要があります",
|
58 |
-
"**获取API使用情况失败**,sensitive_id错误或已过期": "**API使用状況の取得に失敗しました**、sensitive_idが間違っているか、期限切れです",
|
59 |
"**本月使用金额** ": "**今月の使用料金** ",
|
60 |
-
"本月使用金额": "今月の使用料金",
|
61 |
"获取API使用情况失败:": "API使用状況の取得に失敗しました:",
|
62 |
"API密钥更改为了": "APIキーが変更されました",
|
63 |
"JSON解析错误,收到的内容: ": "JSON解析エラー、受信内容: ",
|
@@ -72,13 +64,10 @@
|
|
72 |
"API key为空,请检查是否输入正确。": "APIキーが入力されていません。正しく入力されているか確認してください。",
|
73 |
"请输入对话内容。": "会話内容を入力してください。",
|
74 |
"账单信息不适用": "課金情報は対象外です",
|
75 |
-
"由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)
|
76 |
"切换亮暗色主题": "テーマの明暗切替",
|
77 |
"您的IP区域:未知。": "あなたのIPアドレス地域:不明",
|
78 |
"获取IP地理位置失败。原因:": "IPアドレス地域の取得に失敗しました。理由:",
|
79 |
"。你仍然可以使用聊天功能。": "。あなたはまだチャット機能を使用できます。",
|
80 |
-
"您的IP区域:": "あなたのIPアドレス地域:"
|
81 |
-
|
82 |
-
"生成内容总结中……": "コンテンツ概要を生成しています...",
|
83 |
-
"由于下面的原因,Google 拒绝返回 PaLM 的回答:\n\n": "Googleは以下の理由から、PaLMの回答を返すことを拒否しています:\n\n"
|
84 |
-
}
|
|
|
32 |
"📝 导出为Markdown": "📝 Markdownでエクスポート",
|
33 |
"默认保存于history文件夹": "デフォルトでhistoryフォルダに保存されます",
|
34 |
"高级": "Advanced",
|
35 |
+
"# ⚠️ 务必谨慎更改 ⚠️\n\n如果无法使用请恢复默认设置": "# ⚠️ 変更には慎重に ⚠️\n\nもし動作しない場合は、デフォルト設定に戻してください。",
|
36 |
"参数": "パラメータ",
|
37 |
+
"在这里输入停止符,用英文逗号隔开...": "ここにストップ文字を英語のカンマで区切って入力してください...",
|
38 |
"用于定位滥用行为": "不正行為を特定するために使用されます",
|
39 |
"用户名": "ユーザー名",
|
40 |
"网络设置": "ネットワーク設定",
|
|
|
43 |
"在这里输入代理地址...": "プロキシアドレスを入力してください...",
|
44 |
"代理地址(示例:http://127.0.0.1:10809)": "プロキシアドレス(例:http://127.0.0.1:10809)",
|
45 |
"🔄 设置代理地址": "🔄 プロキシアドレスを設定",
|
46 |
+
"🔙 恢复默认设置": "🔙 デフォルト設定に戻す",
|
|
|
|
|
|
|
|
|
|
|
47 |
"川虎Chat 🚀": "川虎Chat 🚀",
|
48 |
"开始实时传输回答……": "ストリーム出力開始……",
|
49 |
"Token 计数: ": "Token数: ",
|
50 |
",本次对话累计消耗了 ": ", 今の会話で消費合計 ",
|
51 |
"**获取API使用情况失败**": "**API使用状況の取得に失敗しました**",
|
|
|
|
|
52 |
"**本月使用金额** ": "**今月の使用料金** ",
|
|
|
53 |
"获取API使用情况失败:": "API使用状況の取得に失敗しました:",
|
54 |
"API密钥更改为了": "APIキーが変更されました",
|
55 |
"JSON解析错误,收到的内容: ": "JSON解析エラー、受信内容: ",
|
|
|
64 |
"API key为空,请检查是否输入正确。": "APIキーが入力されていません。正しく入力されているか確認してください。",
|
65 |
"请输入对话内容。": "会話内容を入力してください。",
|
66 |
"账单信息不适用": "課金情報は対象外です",
|
67 |
+
"由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536) 和 [明昭MZhao](https://space.bilibili.com/24807452)开发<br />访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "開発:Bilibili [土川虎虎虎](https://space.bilibili.com/29125536) と [明昭MZhao](https://space.bilibili.com/24807452)\n\n最新コードは川虎Chatのサイトへ [GitHubプロジェクト](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
|
68 |
"切换亮暗色主题": "テーマの明暗切替",
|
69 |
"您的IP区域:未知。": "あなたのIPアドレス地域:不明",
|
70 |
"获取IP地理位置失败。原因:": "IPアドレス地域の取得に失敗しました。理由:",
|
71 |
"。你仍然可以使用聊天功能。": "。あなたはまだチャット機能を使用できます。",
|
72 |
+
"您的IP区域:": "あなたのIPアドレス地域:"
|
73 |
+
}
|
|
|
|
|
|
locale/ko_KR.json
DELETED
@@ -1,86 +0,0 @@
|
|
1 |
-
{
|
2 |
-
"未命名对话历史记录": "이름없는 대화 기록",
|
3 |
-
"在这里输入": "여기에 입력하세요",
|
4 |
-
"🧹 新的对话": "🧹 새로운 대화",
|
5 |
-
"🔄 重新生成": "🔄 재생성",
|
6 |
-
"🗑️ 删除最旧对话": "🗑️ 가장 오래된 대화 삭제",
|
7 |
-
"🗑️ 删除最新对话": "🗑️ 최신 대화 삭제",
|
8 |
-
"🗑️ 删除": "🗑️ 삭제",
|
9 |
-
"模型": "LLM 모델",
|
10 |
-
"多账号模式已开启,无需输入key,可直接开始对话": "다중 계정 모드가 활성화되어 있으므로 키를 입력할 필요가 없이 바로 대화를 시작할 수 있습니다",
|
11 |
-
"**发送消息** 或 **提交key** 以显示额度": "**메세지를 전송** 하거나 **Key를 입력**하여 크레딧 표시",
|
12 |
-
"选择模型": "모델 선택",
|
13 |
-
"选择LoRA模型": "LoRA 모델 선택",
|
14 |
-
"实时传输回答": "실시간 전송",
|
15 |
-
"单轮对话": "단일 대화",
|
16 |
-
"使用在线搜索": "온라인 검색 사용",
|
17 |
-
"选择回复语言(针对搜索&索引功能)": "답장 언어 선택 (검색 & 인덱스용)",
|
18 |
-
"上传索引文件": "업로드",
|
19 |
-
"双栏pdf": "2-column pdf",
|
20 |
-
"识别公式": "formula OCR",
|
21 |
-
"在这里输入System Prompt...": "여기에 시스템 프롬프트를 입력하세요...",
|
22 |
-
"加载Prompt模板": "프롬프트 템플릿 불러오기",
|
23 |
-
"选择Prompt模板集合文件": "프롬프트 콜렉션 파일 선택",
|
24 |
-
"🔄 刷新": "🔄 새로고침",
|
25 |
-
"从Prompt模板中加载": "프롬프트 템플릿에서 불러오기",
|
26 |
-
"保存/加载": "저장/불러오기",
|
27 |
-
"保存/加载对话历史记录": "대화 기록 저장/불러오기",
|
28 |
-
"从列表中加载对话": "리스트에서 대화 불러오기",
|
29 |
-
"设置文件名: 默认为.json,可选为.md": "파일 이름 설정: 기본값: .json, 선택: .md",
|
30 |
-
"设置保存文件名": "저장 파일명 설정",
|
31 |
-
"对话历史记录": "대화 기록",
|
32 |
-
"💾 保存对话": "💾 대화 저장",
|
33 |
-
"📝 导出为Markdown": "📝 마크다운으로 내보내기",
|
34 |
-
"默认保存于history文件夹": "히스토리 폴더에 기본 저장",
|
35 |
-
"高级": "고급",
|
36 |
-
"# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ 주의: 변경시 주의하세요. ⚠️",
|
37 |
-
"参数": "파라미터들",
|
38 |
-
"停止符,用英文逗号隔开...": "여기에 정지 토큰 입력, ','로 구분됨...",
|
39 |
-
"用于定位滥用行为": "악용 사례 파악에 활용됨",
|
40 |
-
"用户名": "사용자 이름",
|
41 |
-
"网络设置": "네트워크 설정",
|
42 |
-
"在这里输入API-Host...": "여기에 API host를 입력하세요...",
|
43 |
-
"🔄 切换API地址": "🔄 API 주소 변경",
|
44 |
-
"在这里输入代理地址...": "여기에 프록시 주소를 입력하세요...",
|
45 |
-
"代理地址(示例:http://127.0.0.1:10809)": "프록시 주소 (예: http://127.0.0.1:10809)",
|
46 |
-
"🔄 设置代理地址": "🔄 프록시 주소 설정",
|
47 |
-
"🔙 恢复默认网络设置": "🔙 네트워크 설정 초기화",
|
48 |
-
"🔄 检查更新...": "🔄 업데이트 확인...",
|
49 |
-
"取消": "취소",
|
50 |
-
"更新": "업데이트",
|
51 |
-
"详情": "상세",
|
52 |
-
"好": "예",
|
53 |
-
"川虎Chat 🚀": "Chuanhu Chat 🚀",
|
54 |
-
"开始实时传输回答……": "실시간 응답 출력 시작...",
|
55 |
-
"Token 计数: ": "토큰 수: ",
|
56 |
-
",本次对话累计消耗了 ": ",이 대화의 전체 비용은 ",
|
57 |
-
"**获取API使用情况失败**": "**API 사용량 가져오기 실패**",
|
58 |
-
"**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**API 사용량 가져오기 실패**. `config.json`에 올바른 `sensitive_id`를 입력해야 합니다",
|
59 |
-
"**获取API使用情况失败**,sensitive_id错误或已过期": "**API 사용량 가져오기 실패**. sensitive_id가 잘못되었거나 만료되었습니다",
|
60 |
-
"**本月使用金额** ": "**이번 달 사용금액** ",
|
61 |
-
"本月使用金额": "이번 달 사용금액",
|
62 |
-
"获取API使用情况失败:": "API 사용량 가져오기 실패:",
|
63 |
-
"API密钥更改为了": "API 키가 변경되었습니다.",
|
64 |
-
"JSON解析错误,收到的内容: ": "JSON 파싱 에러, 응답: ",
|
65 |
-
"模型设置为了:": "설정된 모델: ",
|
66 |
-
"☹️发生了错误:": "☹️에러: ",
|
67 |
-
"获取对话时发生错误,请查看后台日志": "대화를 가져오는 중 에러가 발생했습니다. 백그라운드 로그를 확인하세요",
|
68 |
-
"请检查网络连接,或者API-Key是否有效。": "네트워크 연결 또는 API키가 유효한지 확인하세요",
|
69 |
-
"连接超时,无法获取对话。": "연결 시간 초과, 대화를 가져올 수 없습니다.",
|
70 |
-
"读取超时,无法获取对话。": "읽기 시간 초과, 대화를 가져올 수 없습니다.",
|
71 |
-
"代理错误,无法获取对话。": "프록시 에러, 대화를 가져올 수 없습니다.",
|
72 |
-
"SSL错误,无法获取对话。": "SSL 에러, 대화를 가져올 수 없습니다.",
|
73 |
-
"API key为空,请检查是��输入正确。": "API 키가 비어 있습니다. 올바르게 입력되었는지 확인하십세요.",
|
74 |
-
"请输入对话内容。": "대화 내용을 입력하세요.",
|
75 |
-
"账单信息不适用": "청구 정보를 가져올 수 없습니다",
|
76 |
-
"由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)、[明昭MZhao](https://space.bilibili.com/24807452) 和 [Keldos](https://github.com/Keldos-Li) 开发<br />访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "제작: Bilibili [土川虎虎虎](https://space.bilibili.com/29125536), [明昭MZhao](https://space.bilibili.com/24807452), [Keldos](https://github.com/Keldos-Li)\n\n최신 코드 다운로드: [GitHub](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
|
77 |
-
"切换亮暗色主题": "라이트/다크 테마 전환",
|
78 |
-
"您的IP区域:未知。": "IP 지역: 알 수 없음.",
|
79 |
-
"获取IP地理位置失败。原因:": "다음과 같은 이유로 IP 위치를 가져올 수 없습니다. 이유: ",
|
80 |
-
"。你仍然可以使用聊天功能。": ". 채팅 기능을 계속 사용할 수 있습니다.",
|
81 |
-
"您的IP区域:": "당신의 IP 지역: ",
|
82 |
-
"总结": "요약",
|
83 |
-
"生成内容总结中……": "콘텐츠 요약 생성중...",
|
84 |
-
"上传": "업로드",
|
85 |
-
"由于下面的原因,Google 拒绝返回 PaLM 的回答:\n\n": "구글은 다음과 같은 이유로 인해 PaLM의 응답을 거부합니다: \n\n"
|
86 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
locale/sv-SE.json
DELETED
@@ -1,84 +0,0 @@
|
|
1 |
-
{
|
2 |
-
"未命名对话历史记录": "Onämnd Dialoghistorik",
|
3 |
-
"在这里输入": "Skriv in här",
|
4 |
-
"🧹 新的对话": "🧹 Ny Dialog",
|
5 |
-
"🔄 重新生成": "🔄 Regenerera",
|
6 |
-
"🗑️ 删除最旧对话": "🗑️ Ta bort äldsta dialogen",
|
7 |
-
"🗑️ 删除最新对话": "🗑️ Ta bort senaste dialogen",
|
8 |
-
"模型": "Modell",
|
9 |
-
"多账号模式已开启,无需输入key,可直接开始对话": "Flerkontoläge är aktiverat, ingen nyckel behövs, du kan starta dialogen direkt",
|
10 |
-
"**发送消息** 或 **提交key** 以显示额度": "**Skicka meddelande** eller **Skicka in nyckel** för att visa kredit",
|
11 |
-
"选择模型": "Välj Modell",
|
12 |
-
"选择LoRA模型": "Välj LoRA Modell",
|
13 |
-
"实时传输回答": "Strömmande utdata",
|
14 |
-
"单轮对话": "Enkel dialog",
|
15 |
-
"使用在线搜索": "Använd online-sökning",
|
16 |
-
"选择回复语言(针对搜索&索引功能)": "Välj svarspråk (för sök- och indexfunktion)",
|
17 |
-
"上传索引文件": "Ladda upp",
|
18 |
-
"双栏pdf": "Två-kolumns pdf",
|
19 |
-
"识别公式": "Formel OCR",
|
20 |
-
"在这里输入System Prompt...": "Skriv in System Prompt här...",
|
21 |
-
"加载Prompt模板": "Ladda Prompt-mall",
|
22 |
-
"选择Prompt模板集合文件": "Välj Prompt-mall Samlingsfil",
|
23 |
-
"🔄 刷新": "🔄 Uppdatera",
|
24 |
-
"从Prompt模板中加载": "Ladda från Prompt-mall",
|
25 |
-
"保存/加载": "Spara/Ladda",
|
26 |
-
"保存/加载对话历史记录": "Spara/Ladda Dialoghistorik",
|
27 |
-
"从列表中加载对话": "Ladda dialog från lista",
|
28 |
-
"设置文件名: 默认为.json,可选为.md": "Ställ in filnamn: standard är .json, valfritt är .md",
|
29 |
-
"设置保存文件名": "Ställ in sparfilnamn",
|
30 |
-
"对话历史记录": "Dialoghistorik",
|
31 |
-
"💾 保存对话": "💾 Spara Dialog",
|
32 |
-
"📝 导出为Markdown": "📝 Exportera som Markdown",
|
33 |
-
"默认保存于history文件夹": "Sparas som standard i mappen history",
|
34 |
-
"高级": "Avancerat",
|
35 |
-
"# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ Var försiktig med ändringar. ⚠️",
|
36 |
-
"参数": "Parametrar",
|
37 |
-
"停止符,用英文逗号隔开...": "Skriv in stopptecken här, separerade med kommatecken...",
|
38 |
-
"用于定位滥用行为": "Används för att lokalisera missbruk",
|
39 |
-
"用户名": "Användarnamn",
|
40 |
-
"网络设置": "Nätverksinställningar",
|
41 |
-
"在这里输入API-Host...": "Skriv in API-Host här...",
|
42 |
-
"🔄 切换API地址": "🔄 Byt API-adress",
|
43 |
-
"在这里输入代理地址...": "Skriv in proxyadress här...",
|
44 |
-
"代理地址(示例:http://127.0.0.1:10809)": "Proxyadress (exempel: http://127.0.0.1:10809)",
|
45 |
-
"🔄 设置代理地址": "🔄 Ställ in Proxyadress",
|
46 |
-
"🔙 恢复网络默认设置": "🔙 Återställ Nätverksinställningar",
|
47 |
-
"🔄 检查更新...": "🔄 Sök efter uppdateringar...",
|
48 |
-
"取消": "Avbryt",
|
49 |
-
"更新": "Uppdatera",
|
50 |
-
"详情": "Detaljer",
|
51 |
-
"好": "OK",
|
52 |
-
"川虎Chat 🚀": "Chuanhu Chat 🚀",
|
53 |
-
"开始实时传输回答……": "Börjar strömma utdata...",
|
54 |
-
"Token 计数: ": "Tokenräkning: ",
|
55 |
-
",本次对话累计消耗了 ": ", Total kostnad för denna dialog är ",
|
56 |
-
"**获取API使用情况失败**": "**Misslyckades med att hämta API-användning**",
|
57 |
-
"**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**Misslyckades med att hämta API-användning**, korrekt sensitive_id behövs i `config.json`",
|
58 |
-
"**获取API使用情况失败**,sensitive_id错误或已过期": "**Misslyckades med att hämta API-användning**, felaktig eller utgången sensitive_id",
|
59 |
-
"**本月使用金额** ": "**Månadens användning** ",
|
60 |
-
"本月使用金额": "Månadens användning",
|
61 |
-
"获取API使用情况失败:": "Misslyckades med att hämta API-användning:",
|
62 |
-
"API密钥更改为了": "API-nyckeln har ändrats till",
|
63 |
-
"JSON解析错误,收到的内容: ": "JSON-tolkningsfel, mottaget innehåll: ",
|
64 |
-
"模型设置为了:": "Modellen är inställd på: ",
|
65 |
-
"☹️发生了错误:": "☹️Fel: ",
|
66 |
-
"获取对话时发生错误,请查看后台日志": "Ett fel uppstod när dialogen hämtades, kontrollera bakgrundsloggen",
|
67 |
-
"请检查网络连接,或者API-Key是否有效。": "Kontrollera nätverksanslutningen eller om API-nyckeln är giltig.",
|
68 |
-
"连接超时,无法获取对话。": "Anslutningen tog för lång tid, kunde inte hämta dialogen.",
|
69 |
-
"读取超时,无法获取对话。": "Läsningen tog för lång tid, kunde inte hämta dialogen.",
|
70 |
-
"代理错误,无法获取对话。": "Proxyfel, kunde inte hämta dialogen.",
|
71 |
-
"SSL错误,无法获取对话。": "SSL-fel, kunde inte hämta dialogen.",
|
72 |
-
"API key为空,请检查是否输入正确。": "API-nyckeln är tom, kontrollera om den är korrekt inmatad.",
|
73 |
-
"请输入对话内容。": "Ange dialoginnehåll.",
|
74 |
-
"账单信���不适用": "Faktureringsinformation är inte tillämplig",
|
75 |
-
"由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)、[明昭MZhao](https://space.bilibili.com/24807452) 和 [Keldos](https://github.com/Keldos-Li) 开发<br />访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "Utvecklad av Bilibili [土川虎虎虎](https://space.bilibili.com/29125536), [明昭MZhao](https://space.bilibili.com/24807452) och [Keldos](https://github.com/Keldos-Li)\n\nLadda ner senaste koden från [GitHub](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
|
76 |
-
"切换亮暗色主题": "Byt ljus/mörk tema",
|
77 |
-
"您的IP区域:未知。": "Din IP-region: Okänd.",
|
78 |
-
"获取IP地理位置失败。原因:": "Misslyckades med att hämta IP-plats. Orsak: ",
|
79 |
-
"。你仍然可以使用聊天功能。": ". Du kan fortfarande använda chattfunktionen.",
|
80 |
-
"您的IP区域:": "Din IP-region: ",
|
81 |
-
"总结": "Sammanfatta",
|
82 |
-
"生成内容总结中……": "Genererar innehållssammanfattning...",
|
83 |
-
"由于下面的原因,Google 拒绝返回 PaLM 的回答:\n\n": "På grund av följande skäl vägrar Google att ge ett svar till PaLM: \n\n"
|
84 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
modules/base_model.py
ADDED
@@ -0,0 +1,561 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
from typing import TYPE_CHECKING, List
|
3 |
+
|
4 |
+
import logging
|
5 |
+
import json
|
6 |
+
import commentjson as cjson
|
7 |
+
import os
|
8 |
+
import sys
|
9 |
+
import requests
|
10 |
+
import urllib3
|
11 |
+
import traceback
|
12 |
+
|
13 |
+
from tqdm import tqdm
|
14 |
+
import colorama
|
15 |
+
from duckduckgo_search import ddg
|
16 |
+
import asyncio
|
17 |
+
import aiohttp
|
18 |
+
from enum import Enum
|
19 |
+
|
20 |
+
from .presets import *
|
21 |
+
from .llama_func import *
|
22 |
+
from .utils import *
|
23 |
+
from . import shared
|
24 |
+
from .config import retrieve_proxy
|
25 |
+
|
26 |
+
|
27 |
+
class ModelType(Enum):
|
28 |
+
Unknown = -1
|
29 |
+
OpenAI = 0
|
30 |
+
ChatGLM = 1
|
31 |
+
LLaMA = 2
|
32 |
+
XMChat = 3
|
33 |
+
|
34 |
+
@classmethod
|
35 |
+
def get_type(cls, model_name: str):
|
36 |
+
model_type = None
|
37 |
+
model_name_lower = model_name.lower()
|
38 |
+
if "gpt" in model_name_lower:
|
39 |
+
model_type = ModelType.OpenAI
|
40 |
+
elif "chatglm" in model_name_lower:
|
41 |
+
model_type = ModelType.ChatGLM
|
42 |
+
elif "llama" in model_name_lower or "alpaca" in model_name_lower:
|
43 |
+
model_type = ModelType.LLaMA
|
44 |
+
elif "xmchat" in model_name_lower:
|
45 |
+
model_type = ModelType.XMChat
|
46 |
+
else:
|
47 |
+
model_type = ModelType.Unknown
|
48 |
+
return model_type
|
49 |
+
|
50 |
+
|
51 |
+
class BaseLLMModel:
|
52 |
+
def __init__(
|
53 |
+
self,
|
54 |
+
model_name,
|
55 |
+
system_prompt="",
|
56 |
+
temperature=1.0,
|
57 |
+
top_p=1.0,
|
58 |
+
n_choices=1,
|
59 |
+
stop=None,
|
60 |
+
max_generation_token=None,
|
61 |
+
presence_penalty=0,
|
62 |
+
frequency_penalty=0,
|
63 |
+
logit_bias=None,
|
64 |
+
user="",
|
65 |
+
) -> None:
|
66 |
+
self.history = []
|
67 |
+
self.all_token_counts = []
|
68 |
+
self.model_name = model_name
|
69 |
+
self.model_type = ModelType.get_type(model_name)
|
70 |
+
try:
|
71 |
+
self.token_upper_limit = MODEL_TOKEN_LIMIT[model_name]
|
72 |
+
except KeyError:
|
73 |
+
self.token_upper_limit = DEFAULT_TOKEN_LIMIT
|
74 |
+
self.interrupted = False
|
75 |
+
self.system_prompt = system_prompt
|
76 |
+
self.api_key = None
|
77 |
+
self.need_api_key = False
|
78 |
+
self.single_turn = False
|
79 |
+
|
80 |
+
self.temperature = temperature
|
81 |
+
self.top_p = top_p
|
82 |
+
self.n_choices = n_choices
|
83 |
+
self.stop_sequence = stop
|
84 |
+
self.max_generation_token = None
|
85 |
+
self.presence_penalty = presence_penalty
|
86 |
+
self.frequency_penalty = frequency_penalty
|
87 |
+
self.logit_bias = logit_bias
|
88 |
+
self.user_identifier = user
|
89 |
+
|
90 |
+
def get_answer_stream_iter(self):
|
91 |
+
"""stream predict, need to be implemented
|
92 |
+
conversations are stored in self.history, with the most recent question, in OpenAI format
|
93 |
+
should return a generator, each time give the next word (str) in the answer
|
94 |
+
"""
|
95 |
+
logging.warning("stream predict not implemented, using at once predict instead")
|
96 |
+
response, _ = self.get_answer_at_once()
|
97 |
+
yield response
|
98 |
+
|
99 |
+
def get_answer_at_once(self):
|
100 |
+
"""predict at once, need to be implemented
|
101 |
+
conversations are stored in self.history, with the most recent question, in OpenAI format
|
102 |
+
Should return:
|
103 |
+
the answer (str)
|
104 |
+
total token count (int)
|
105 |
+
"""
|
106 |
+
logging.warning("at once predict not implemented, using stream predict instead")
|
107 |
+
response_iter = self.get_answer_stream_iter()
|
108 |
+
count = 0
|
109 |
+
for response in response_iter:
|
110 |
+
count += 1
|
111 |
+
return response, sum(self.all_token_counts) + count
|
112 |
+
|
113 |
+
def billing_info(self):
|
114 |
+
"""get billing infomation, inplement if needed"""
|
115 |
+
logging.warning("billing info not implemented, using default")
|
116 |
+
return BILLING_NOT_APPLICABLE_MSG
|
117 |
+
|
118 |
+
def count_token(self, user_input):
|
119 |
+
"""get token count from input, implement if needed"""
|
120 |
+
logging.warning("token count not implemented, using default")
|
121 |
+
return len(user_input)
|
122 |
+
|
123 |
+
def stream_next_chatbot(self, inputs, chatbot, fake_input=None, display_append=""):
|
124 |
+
def get_return_value():
|
125 |
+
return chatbot, status_text
|
126 |
+
|
127 |
+
status_text = i18n("开始实时传输回答……")
|
128 |
+
if fake_input:
|
129 |
+
chatbot.append((fake_input, ""))
|
130 |
+
else:
|
131 |
+
chatbot.append((inputs, ""))
|
132 |
+
|
133 |
+
user_token_count = self.count_token(inputs)
|
134 |
+
self.all_token_counts.append(user_token_count)
|
135 |
+
logging.debug(f"输入token计数: {user_token_count}")
|
136 |
+
|
137 |
+
stream_iter = self.get_answer_stream_iter()
|
138 |
+
|
139 |
+
for partial_text in stream_iter:
|
140 |
+
chatbot[-1] = (chatbot[-1][0], partial_text + display_append)
|
141 |
+
self.all_token_counts[-1] += 1
|
142 |
+
status_text = self.token_message()
|
143 |
+
yield get_return_value()
|
144 |
+
if self.interrupted:
|
145 |
+
self.recover()
|
146 |
+
break
|
147 |
+
self.history.append(construct_assistant(partial_text))
|
148 |
+
|
149 |
+
def next_chatbot_at_once(self, inputs, chatbot, fake_input=None, display_append=""):
|
150 |
+
if fake_input:
|
151 |
+
chatbot.append((fake_input, ""))
|
152 |
+
else:
|
153 |
+
chatbot.append((inputs, ""))
|
154 |
+
if fake_input is not None:
|
155 |
+
user_token_count = self.count_token(fake_input)
|
156 |
+
else:
|
157 |
+
user_token_count = self.count_token(inputs)
|
158 |
+
self.all_token_counts.append(user_token_count)
|
159 |
+
ai_reply, total_token_count = self.get_answer_at_once()
|
160 |
+
self.history.append(construct_assistant(ai_reply))
|
161 |
+
if fake_input is not None:
|
162 |
+
self.history[-2] = construct_user(fake_input)
|
163 |
+
chatbot[-1] = (chatbot[-1][0], ai_reply + display_append)
|
164 |
+
if fake_input is not None:
|
165 |
+
self.all_token_counts[-1] += count_token(construct_assistant(ai_reply))
|
166 |
+
else:
|
167 |
+
self.all_token_counts[-1] = total_token_count - sum(self.all_token_counts)
|
168 |
+
status_text = self.token_message()
|
169 |
+
return chatbot, status_text
|
170 |
+
|
171 |
+
def handle_file_upload(self, files, chatbot):
|
172 |
+
"""if the model accepts multi modal input, implement this function"""
|
173 |
+
status = gr.Markdown.update()
|
174 |
+
if files:
|
175 |
+
construct_index(self.api_key, file_src=files)
|
176 |
+
status = "索引构建完成"
|
177 |
+
return gr.Files.update(), chatbot, status
|
178 |
+
|
179 |
+
def prepare_inputs(self, real_inputs, use_websearch, files, reply_language, chatbot):
|
180 |
+
fake_inputs = None
|
181 |
+
display_append = []
|
182 |
+
limited_context = False
|
183 |
+
fake_inputs = real_inputs
|
184 |
+
if files:
|
185 |
+
from llama_index.indices.vector_store.base_query import GPTVectorStoreIndexQuery
|
186 |
+
from llama_index.indices.query.schema import QueryBundle
|
187 |
+
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
|
188 |
+
from langchain.chat_models import ChatOpenAI
|
189 |
+
from llama_index import (
|
190 |
+
GPTSimpleVectorIndex,
|
191 |
+
ServiceContext,
|
192 |
+
LangchainEmbedding,
|
193 |
+
OpenAIEmbedding,
|
194 |
+
)
|
195 |
+
limited_context = True
|
196 |
+
msg = "加载索引中……"
|
197 |
+
logging.info(msg)
|
198 |
+
# yield chatbot + [(inputs, "")], msg
|
199 |
+
index = construct_index(self.api_key, file_src=files)
|
200 |
+
assert index is not None, "获取索引失败"
|
201 |
+
msg = "索引获取成功,生成回答中……"
|
202 |
+
logging.info(msg)
|
203 |
+
if local_embedding or self.model_type != ModelType.OpenAI:
|
204 |
+
embed_model = LangchainEmbedding(HuggingFaceEmbeddings(model_name = "sentence-transformers/distiluse-base-multilingual-cased-v2"))
|
205 |
+
else:
|
206 |
+
embed_model = OpenAIEmbedding()
|
207 |
+
# yield chatbot + [(inputs, "")], msg
|
208 |
+
with retrieve_proxy():
|
209 |
+
prompt_helper = PromptHelper(
|
210 |
+
max_input_size=4096,
|
211 |
+
num_output=5,
|
212 |
+
max_chunk_overlap=20,
|
213 |
+
chunk_size_limit=600,
|
214 |
+
)
|
215 |
+
from llama_index import ServiceContext
|
216 |
+
|
217 |
+
service_context = ServiceContext.from_defaults(
|
218 |
+
prompt_helper=prompt_helper, embed_model=embed_model
|
219 |
+
)
|
220 |
+
query_object = GPTVectorStoreIndexQuery(
|
221 |
+
index.index_struct,
|
222 |
+
service_context=service_context,
|
223 |
+
similarity_top_k=5,
|
224 |
+
vector_store=index._vector_store,
|
225 |
+
docstore=index._docstore,
|
226 |
+
)
|
227 |
+
query_bundle = QueryBundle(real_inputs)
|
228 |
+
nodes = query_object.retrieve(query_bundle)
|
229 |
+
reference_results = [n.node.text for n in nodes]
|
230 |
+
reference_results = add_source_numbers(reference_results, use_source=False)
|
231 |
+
display_append = add_details(reference_results)
|
232 |
+
display_append = "\n\n" + "".join(display_append)
|
233 |
+
real_inputs = (
|
234 |
+
replace_today(PROMPT_TEMPLATE)
|
235 |
+
.replace("{query_str}", real_inputs)
|
236 |
+
.replace("{context_str}", "\n\n".join(reference_results))
|
237 |
+
.replace("{reply_language}", reply_language)
|
238 |
+
)
|
239 |
+
elif use_websearch:
|
240 |
+
limited_context = True
|
241 |
+
search_results = ddg(real_inputs, max_results=5)
|
242 |
+
reference_results = []
|
243 |
+
for idx, result in enumerate(search_results):
|
244 |
+
logging.debug(f"搜索结果{idx + 1}:{result}")
|
245 |
+
domain_name = urllib3.util.parse_url(result["href"]).host
|
246 |
+
reference_results.append([result["body"], result["href"]])
|
247 |
+
display_append.append(
|
248 |
+
# f"{idx+1}. [{domain_name}]({result['href']})\n"
|
249 |
+
f"<li><a href=\"{result['href']}\" target=\"_blank\">{domain_name}</a></li>\n"
|
250 |
+
)
|
251 |
+
reference_results = add_source_numbers(reference_results)
|
252 |
+
display_append = "<ol>\n\n" + "".join(display_append) + "</ol>"
|
253 |
+
real_inputs = (
|
254 |
+
replace_today(WEBSEARCH_PTOMPT_TEMPLATE)
|
255 |
+
.replace("{query}", real_inputs)
|
256 |
+
.replace("{web_results}", "\n\n".join(reference_results))
|
257 |
+
.replace("{reply_language}", reply_language)
|
258 |
+
)
|
259 |
+
else:
|
260 |
+
display_append = ""
|
261 |
+
return limited_context, fake_inputs, display_append, real_inputs, chatbot
|
262 |
+
|
263 |
+
def predict(
|
264 |
+
self,
|
265 |
+
inputs,
|
266 |
+
chatbot,
|
267 |
+
stream=False,
|
268 |
+
use_websearch=False,
|
269 |
+
files=None,
|
270 |
+
reply_language="中文",
|
271 |
+
should_check_token_count=True,
|
272 |
+
): # repetition_penalty, top_k
|
273 |
+
|
274 |
+
status_text = "开始生成回答……"
|
275 |
+
logging.info(
|
276 |
+
"输入为:" + colorama.Fore.BLUE + f"{inputs}" + colorama.Style.RESET_ALL
|
277 |
+
)
|
278 |
+
if should_check_token_count:
|
279 |
+
yield chatbot + [(inputs, "")], status_text
|
280 |
+
if reply_language == "跟随问题语言(不稳定)":
|
281 |
+
reply_language = "the same language as the question, such as English, 中文, 日本語, Español, Français, or Deutsch."
|
282 |
+
|
283 |
+
limited_context, fake_inputs, display_append, inputs, chatbot = self.prepare_inputs(real_inputs=inputs, use_websearch=use_websearch, files=files, reply_language=reply_language, chatbot=chatbot)
|
284 |
+
yield chatbot + [(fake_inputs, "")], status_text
|
285 |
+
|
286 |
+
if (
|
287 |
+
self.need_api_key and
|
288 |
+
self.api_key is None
|
289 |
+
and not shared.state.multi_api_key
|
290 |
+
):
|
291 |
+
status_text = STANDARD_ERROR_MSG + NO_APIKEY_MSG
|
292 |
+
logging.info(status_text)
|
293 |
+
chatbot.append((inputs, ""))
|
294 |
+
if len(self.history) == 0:
|
295 |
+
self.history.append(construct_user(inputs))
|
296 |
+
self.history.append("")
|
297 |
+
self.all_token_counts.append(0)
|
298 |
+
else:
|
299 |
+
self.history[-2] = construct_user(inputs)
|
300 |
+
yield chatbot + [(inputs, "")], status_text
|
301 |
+
return
|
302 |
+
elif len(inputs.strip()) == 0:
|
303 |
+
status_text = STANDARD_ERROR_MSG + NO_INPUT_MSG
|
304 |
+
logging.info(status_text)
|
305 |
+
yield chatbot + [(inputs, "")], status_text
|
306 |
+
return
|
307 |
+
|
308 |
+
if self.single_turn:
|
309 |
+
self.history = []
|
310 |
+
self.all_token_counts = []
|
311 |
+
self.history.append(construct_user(inputs))
|
312 |
+
|
313 |
+
try:
|
314 |
+
if stream:
|
315 |
+
logging.debug("使用流式传输")
|
316 |
+
iter = self.stream_next_chatbot(
|
317 |
+
inputs,
|
318 |
+
chatbot,
|
319 |
+
fake_input=fake_inputs,
|
320 |
+
display_append=display_append,
|
321 |
+
)
|
322 |
+
for chatbot, status_text in iter:
|
323 |
+
yield chatbot, status_text
|
324 |
+
else:
|
325 |
+
logging.debug("不使用流式传输")
|
326 |
+
chatbot, status_text = self.next_chatbot_at_once(
|
327 |
+
inputs,
|
328 |
+
chatbot,
|
329 |
+
fake_input=fake_inputs,
|
330 |
+
display_append=display_append,
|
331 |
+
)
|
332 |
+
yield chatbot, status_text
|
333 |
+
except Exception as e:
|
334 |
+
traceback.print_exc()
|
335 |
+
status_text = STANDARD_ERROR_MSG + str(e)
|
336 |
+
yield chatbot, status_text
|
337 |
+
|
338 |
+
if len(self.history) > 1 and self.history[-1]["content"] != inputs:
|
339 |
+
logging.info(
|
340 |
+
"回答为:"
|
341 |
+
+ colorama.Fore.BLUE
|
342 |
+
+ f"{self.history[-1]['content']}"
|
343 |
+
+ colorama.Style.RESET_ALL
|
344 |
+
)
|
345 |
+
|
346 |
+
if limited_context:
|
347 |
+
# self.history = self.history[-4:]
|
348 |
+
# self.all_token_counts = self.all_token_counts[-2:]
|
349 |
+
self.history = []
|
350 |
+
self.all_token_counts = []
|
351 |
+
|
352 |
+
max_token = self.token_upper_limit - TOKEN_OFFSET
|
353 |
+
|
354 |
+
if sum(self.all_token_counts) > max_token and should_check_token_count:
|
355 |
+
count = 0
|
356 |
+
while (
|
357 |
+
sum(self.all_token_counts)
|
358 |
+
> self.token_upper_limit * REDUCE_TOKEN_FACTOR
|
359 |
+
and sum(self.all_token_counts) > 0
|
360 |
+
):
|
361 |
+
count += 1
|
362 |
+
del self.all_token_counts[0]
|
363 |
+
del self.history[:2]
|
364 |
+
logging.info(status_text)
|
365 |
+
status_text = f"为了防止token超限,模型忘记了早期的 {count} 轮对话"
|
366 |
+
yield chatbot, status_text
|
367 |
+
|
368 |
+
def retry(
|
369 |
+
self,
|
370 |
+
chatbot,
|
371 |
+
stream=False,
|
372 |
+
use_websearch=False,
|
373 |
+
files=None,
|
374 |
+
reply_language="中文",
|
375 |
+
):
|
376 |
+
logging.debug("重试中……")
|
377 |
+
if len(self.history) > 0:
|
378 |
+
inputs = self.history[-2]["content"]
|
379 |
+
del self.history[-2:]
|
380 |
+
self.all_token_counts.pop()
|
381 |
+
elif len(chatbot) > 0:
|
382 |
+
inputs = chatbot[-1][0]
|
383 |
+
else:
|
384 |
+
yield chatbot, f"{STANDARD_ERROR_MSG}上下文是空的"
|
385 |
+
return
|
386 |
+
|
387 |
+
iter = self.predict(
|
388 |
+
inputs,
|
389 |
+
chatbot,
|
390 |
+
stream=stream,
|
391 |
+
use_websearch=use_websearch,
|
392 |
+
files=files,
|
393 |
+
reply_language=reply_language,
|
394 |
+
)
|
395 |
+
for x in iter:
|
396 |
+
yield x
|
397 |
+
logging.debug("重试完毕")
|
398 |
+
|
399 |
+
# def reduce_token_size(self, chatbot):
|
400 |
+
# logging.info("开始减少token数量……")
|
401 |
+
# chatbot, status_text = self.next_chatbot_at_once(
|
402 |
+
# summarize_prompt,
|
403 |
+
# chatbot
|
404 |
+
# )
|
405 |
+
# max_token_count = self.token_upper_limit * REDUCE_TOKEN_FACTOR
|
406 |
+
# num_chat = find_n(self.all_token_counts, max_token_count)
|
407 |
+
# logging.info(f"previous_token_count: {self.all_token_counts}, keeping {num_chat} chats")
|
408 |
+
# chatbot = chatbot[:-1]
|
409 |
+
# self.history = self.history[-2*num_chat:] if num_chat > 0 else []
|
410 |
+
# self.all_token_counts = self.all_token_counts[-num_chat:] if num_chat > 0 else []
|
411 |
+
# msg = f"保留了最近{num_chat}轮对话"
|
412 |
+
# logging.info(msg)
|
413 |
+
# logging.info("减少token数量完毕")
|
414 |
+
# return chatbot, msg + "," + self.token_message(self.all_token_counts if len(self.all_token_counts) > 0 else [0])
|
415 |
+
|
416 |
+
def interrupt(self):
|
417 |
+
self.interrupted = True
|
418 |
+
|
419 |
+
def recover(self):
|
420 |
+
self.interrupted = False
|
421 |
+
|
422 |
+
def set_token_upper_limit(self, new_upper_limit):
|
423 |
+
self.token_upper_limit = new_upper_limit
|
424 |
+
print(f"token上限设置为{new_upper_limit}")
|
425 |
+
|
426 |
+
def set_temperature(self, new_temperature):
|
427 |
+
self.temperature = new_temperature
|
428 |
+
|
429 |
+
def set_top_p(self, new_top_p):
|
430 |
+
self.top_p = new_top_p
|
431 |
+
|
432 |
+
def set_n_choices(self, new_n_choices):
|
433 |
+
self.n_choices = new_n_choices
|
434 |
+
|
435 |
+
def set_stop_sequence(self, new_stop_sequence: str):
|
436 |
+
new_stop_sequence = new_stop_sequence.split(",")
|
437 |
+
self.stop_sequence = new_stop_sequence
|
438 |
+
|
439 |
+
def set_max_tokens(self, new_max_tokens):
|
440 |
+
self.max_generation_token = new_max_tokens
|
441 |
+
|
442 |
+
def set_presence_penalty(self, new_presence_penalty):
|
443 |
+
self.presence_penalty = new_presence_penalty
|
444 |
+
|
445 |
+
def set_frequency_penalty(self, new_frequency_penalty):
|
446 |
+
self.frequency_penalty = new_frequency_penalty
|
447 |
+
|
448 |
+
def set_logit_bias(self, logit_bias):
|
449 |
+
logit_bias = logit_bias.split()
|
450 |
+
bias_map = {}
|
451 |
+
encoding = tiktoken.get_encoding("cl100k_base")
|
452 |
+
for line in logit_bias:
|
453 |
+
word, bias_amount = line.split(":")
|
454 |
+
if word:
|
455 |
+
for token in encoding.encode(word):
|
456 |
+
bias_map[token] = float(bias_amount)
|
457 |
+
self.logit_bias = bias_map
|
458 |
+
|
459 |
+
def set_user_identifier(self, new_user_identifier):
|
460 |
+
self.user_identifier = new_user_identifier
|
461 |
+
|
462 |
+
def set_system_prompt(self, new_system_prompt):
|
463 |
+
self.system_prompt = new_system_prompt
|
464 |
+
|
465 |
+
def set_key(self, new_access_key):
|
466 |
+
self.api_key = new_access_key.strip()
|
467 |
+
msg = i18n("API密钥更改为了") + hide_middle_chars(self.api_key)
|
468 |
+
logging.info(msg)
|
469 |
+
return self.api_key, msg
|
470 |
+
|
471 |
+
def set_single_turn(self, new_single_turn):
|
472 |
+
self.single_turn = new_single_turn
|
473 |
+
|
474 |
+
def reset(self):
|
475 |
+
self.history = []
|
476 |
+
self.all_token_counts = []
|
477 |
+
self.interrupted = False
|
478 |
+
return [], self.token_message([0])
|
479 |
+
|
480 |
+
def delete_first_conversation(self):
|
481 |
+
if self.history:
|
482 |
+
del self.history[:2]
|
483 |
+
del self.all_token_counts[0]
|
484 |
+
return self.token_message()
|
485 |
+
|
486 |
+
def delete_last_conversation(self, chatbot):
|
487 |
+
if len(chatbot) > 0 and STANDARD_ERROR_MSG in chatbot[-1][1]:
|
488 |
+
msg = "由于包含报错信息,只删除chatbot记录"
|
489 |
+
chatbot.pop()
|
490 |
+
return chatbot, self.history
|
491 |
+
if len(self.history) > 0:
|
492 |
+
self.history.pop()
|
493 |
+
self.history.pop()
|
494 |
+
if len(chatbot) > 0:
|
495 |
+
msg = "删除了一组chatbot对话"
|
496 |
+
chatbot.pop()
|
497 |
+
if len(self.all_token_counts) > 0:
|
498 |
+
msg = "删除了一组对话的token计数记录"
|
499 |
+
self.all_token_counts.pop()
|
500 |
+
msg = "删除了一组对话"
|
501 |
+
return chatbot, msg
|
502 |
+
|
503 |
+
def token_message(self, token_lst=None):
|
504 |
+
if token_lst is None:
|
505 |
+
token_lst = self.all_token_counts
|
506 |
+
token_sum = 0
|
507 |
+
for i in range(len(token_lst)):
|
508 |
+
token_sum += sum(token_lst[: i + 1])
|
509 |
+
return i18n("Token 计数: ") + f"{sum(token_lst)}" + i18n(",本次对话累计消耗了 ") + f"{token_sum} tokens"
|
510 |
+
|
511 |
+
def save_chat_history(self, filename, chatbot, user_name):
|
512 |
+
if filename == "":
|
513 |
+
return
|
514 |
+
if not filename.endswith(".json"):
|
515 |
+
filename += ".json"
|
516 |
+
return save_file(filename, self.system_prompt, self.history, chatbot, user_name)
|
517 |
+
|
518 |
+
def export_markdown(self, filename, chatbot, user_name):
|
519 |
+
if filename == "":
|
520 |
+
return
|
521 |
+
if not filename.endswith(".md"):
|
522 |
+
filename += ".md"
|
523 |
+
return save_file(filename, self.system_prompt, self.history, chatbot, user_name)
|
524 |
+
|
525 |
+
def load_chat_history(self, filename, chatbot, user_name):
|
526 |
+
logging.debug(f"{user_name} 加载对话历史中……")
|
527 |
+
if type(filename) != str:
|
528 |
+
filename = filename.name
|
529 |
+
try:
|
530 |
+
with open(os.path.join(HISTORY_DIR, user_name, filename), "r") as f:
|
531 |
+
json_s = json.load(f)
|
532 |
+
try:
|
533 |
+
if type(json_s["history"][0]) == str:
|
534 |
+
logging.info("历史记录格式为旧版,正在转换……")
|
535 |
+
new_history = []
|
536 |
+
for index, item in enumerate(json_s["history"]):
|
537 |
+
if index % 2 == 0:
|
538 |
+
new_history.append(construct_user(item))
|
539 |
+
else:
|
540 |
+
new_history.append(construct_assistant(item))
|
541 |
+
json_s["history"] = new_history
|
542 |
+
logging.info(new_history)
|
543 |
+
except:
|
544 |
+
# 没有对话历史
|
545 |
+
pass
|
546 |
+
logging.debug(f"{user_name} 加载对话历史完毕")
|
547 |
+
self.history = json_s["history"]
|
548 |
+
return filename, json_s["system"], json_s["chatbot"]
|
549 |
+
except FileNotFoundError:
|
550 |
+
logging.warning(f"{user_name} 没有找到对话历史文件,不执行任何操作")
|
551 |
+
return filename, self.system_prompt, chatbot
|
552 |
+
|
553 |
+
def like(self):
|
554 |
+
"""like the last response, implement if needed
|
555 |
+
"""
|
556 |
+
return gr.update()
|
557 |
+
|
558 |
+
def dislike(self):
|
559 |
+
"""dislike the last response, implement if needed
|
560 |
+
"""
|
561 |
+
return gr.update()
|
modules/config.py
CHANGED
@@ -11,7 +11,6 @@ from . import presets
|
|
11 |
|
12 |
__all__ = [
|
13 |
"my_api_key",
|
14 |
-
"sensitive_id",
|
15 |
"authflag",
|
16 |
"auth_list",
|
17 |
"dockerflag",
|
@@ -24,11 +23,8 @@ __all__ = [
|
|
24 |
"server_name",
|
25 |
"server_port",
|
26 |
"share",
|
27 |
-
"check_update",
|
28 |
-
"latex_delimiters_set",
|
29 |
"hide_history_when_not_logged_in",
|
30 |
-
"default_chuanhu_assistant_model"
|
31 |
-
"show_api_billing"
|
32 |
]
|
33 |
|
34 |
# 添加一个统一的config文件,避免文件过多造成的疑惑(优先级最低)
|
@@ -39,22 +35,10 @@ if os.path.exists("config.json"):
|
|
39 |
else:
|
40 |
config = {}
|
41 |
|
42 |
-
|
43 |
-
def load_config_to_environ(key_list):
|
44 |
-
global config
|
45 |
-
for key in key_list:
|
46 |
-
if key in config:
|
47 |
-
os.environ[key.upper()] = os.environ.get(key.upper(), config[key])
|
48 |
-
|
49 |
-
|
50 |
lang_config = config.get("language", "auto")
|
51 |
language = os.environ.get("LANGUAGE", lang_config)
|
52 |
|
53 |
-
hide_history_when_not_logged_in = config.get(
|
54 |
-
"hide_history_when_not_logged_in", False)
|
55 |
-
check_update = config.get("check_update", True)
|
56 |
-
show_api_billing = config.get("show_api_billing", False)
|
57 |
-
show_api_billing = bool(os.environ.get("SHOW_API_BILLING", show_api_billing))
|
58 |
|
59 |
if os.path.exists("api_key.txt"):
|
60 |
logging.info("检测到api_key.txt文件,正在进行迁移...")
|
@@ -68,39 +52,26 @@ if os.path.exists("auth.json"):
|
|
68 |
logging.info("检测到auth.json文件,正在进行迁移...")
|
69 |
auth_list = []
|
70 |
with open("auth.json", "r", encoding='utf-8') as f:
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
config["users"] = auth_list
|
79 |
os.rename("auth.json", "auth(deprecated).json")
|
80 |
with open("config.json", "w", encoding='utf-8') as f:
|
81 |
json.dump(config, f, indent=4, ensure_ascii=False)
|
82 |
|
83 |
-
|
84 |
dockerflag = config.get("dockerflag", False)
|
85 |
if os.environ.get("dockerrun") == "yes":
|
86 |
dockerflag = True
|
87 |
|
88 |
-
|
89 |
my_api_key = config.get("openai_api_key", "")
|
90 |
my_api_key = os.environ.get("OPENAI_API_KEY", my_api_key)
|
91 |
-
os.environ["OPENAI_API_KEY"] = my_api_key
|
92 |
-
os.environ["OPENAI_EMBEDDING_API_KEY"] = my_api_key
|
93 |
-
|
94 |
-
if config.get("legacy_api_usage", False):
|
95 |
-
sensitive_id = config.get("sensitive_id", "")
|
96 |
-
sensitive_id = os.environ.get("SENSITIVE_ID", sensitive_id)
|
97 |
-
else:
|
98 |
-
sensitive_id = my_api_key
|
99 |
-
|
100 |
-
google_palm_api_key = config.get("google_palm_api_key", "")
|
101 |
-
google_palm_api_key = os.environ.get(
|
102 |
-
"GOOGLE_PALM_API_KEY", google_palm_api_key)
|
103 |
-
os.environ["GOOGLE_PALM_API_KEY"] = google_palm_api_key
|
104 |
|
105 |
xmchat_api_key = config.get("xmchat_api_key", "")
|
106 |
os.environ["XMCHAT_API_KEY"] = xmchat_api_key
|
@@ -110,14 +81,11 @@ os.environ["MINIMAX_API_KEY"] = minimax_api_key
|
|
110 |
minimax_group_id = config.get("minimax_group_id", "")
|
111 |
os.environ["MINIMAX_GROUP_ID"] = minimax_group_id
|
112 |
|
113 |
-
load_config_to_environ(["openai_api_type", "azure_openai_api_key", "azure_openai_api_base_url",
|
114 |
-
"azure_openai_api_version", "azure_deployment_name", "azure_embedding_deployment_name", "azure_embedding_model_name"])
|
115 |
-
|
116 |
|
117 |
usage_limit = os.environ.get("USAGE_LIMIT", config.get("usage_limit", 120))
|
118 |
|
119 |
-
|
120 |
-
multi_api_key = config.get("multi_api_key", False)
|
121 |
if multi_api_key:
|
122 |
api_key_list = config.get("api_key_list", [])
|
123 |
if len(api_key_list) == 0:
|
@@ -125,26 +93,21 @@ if multi_api_key:
|
|
125 |
sys.exit(1)
|
126 |
shared.state.set_api_key_queue(api_key_list)
|
127 |
|
128 |
-
auth_list = config.get("users", [])
|
129 |
authflag = len(auth_list) > 0 # 是否开启认证的状态值,改为判断auth_list长度
|
130 |
|
131 |
# 处理自定义的api_host,优先读环境变量的配置,如果存在则自动装配
|
132 |
-
api_host = os.environ.get(
|
133 |
-
"OPENAI_API_BASE", config.get("openai_api_base", None))
|
134 |
if api_host is not None:
|
135 |
shared.state.set_api_host(api_host)
|
136 |
-
os.environ["OPENAI_API_BASE"] = f"{api_host}/v1"
|
137 |
-
logging.info(f"OpenAI API Base set to: {os.environ['OPENAI_API_BASE']}")
|
138 |
|
139 |
-
default_chuanhu_assistant_model = config.get(
|
140 |
-
"default_chuanhu_assistant_model", "gpt-3.5-turbo")
|
141 |
for x in ["GOOGLE_CSE_ID", "GOOGLE_API_KEY", "WOLFRAM_ALPHA_APPID", "SERPAPI_API_KEY"]:
|
142 |
if config.get(x, None) is not None:
|
143 |
os.environ[x] = config[x]
|
144 |
|
145 |
-
|
146 |
@contextmanager
|
147 |
-
def retrieve_openai_api(api_key=None):
|
148 |
old_api_key = os.environ.get("OPENAI_API_KEY", "")
|
149 |
if api_key is None:
|
150 |
os.environ["OPENAI_API_KEY"] = my_api_key
|
@@ -154,26 +117,24 @@ def retrieve_openai_api(api_key=None):
|
|
154 |
yield api_key
|
155 |
os.environ["OPENAI_API_KEY"] = old_api_key
|
156 |
|
157 |
-
|
158 |
-
# 处理log
|
159 |
log_level = config.get("log_level", "INFO")
|
160 |
logging.basicConfig(
|
161 |
level=log_level,
|
162 |
format="%(asctime)s [%(levelname)s] [%(filename)s:%(lineno)d] %(message)s",
|
163 |
)
|
164 |
|
165 |
-
|
166 |
-
http_proxy =
|
167 |
-
https_proxy =
|
168 |
-
http_proxy =
|
169 |
-
https_proxy =
|
170 |
|
171 |
# 重置系统变量,在不需要设置的时候不设置环境变量,以免引起全局代理报错
|
172 |
os.environ["HTTP_PROXY"] = ""
|
173 |
os.environ["HTTPS_PROXY"] = ""
|
174 |
|
175 |
-
local_embedding = config.get("local_embedding", False)
|
176 |
-
|
177 |
|
178 |
@contextmanager
|
179 |
def retrieve_proxy(proxy=None):
|
@@ -190,62 +151,22 @@ def retrieve_proxy(proxy=None):
|
|
190 |
old_var = os.environ["HTTP_PROXY"], os.environ["HTTPS_PROXY"]
|
191 |
os.environ["HTTP_PROXY"] = http_proxy
|
192 |
os.environ["HTTPS_PROXY"] = https_proxy
|
193 |
-
yield http_proxy, https_proxy
|
194 |
|
195 |
# return old proxy
|
196 |
os.environ["HTTP_PROXY"], os.environ["HTTPS_PROXY"] = old_var
|
197 |
|
198 |
|
199 |
-
|
200 |
-
user_latex_option = config.get("latex_option", "default")
|
201 |
-
if user_latex_option == "default":
|
202 |
-
latex_delimiters_set = [
|
203 |
-
{"left": "$$", "right": "$$", "display": True},
|
204 |
-
{"left": "$", "right": "$", "display": False},
|
205 |
-
{"left": "\\(", "right": "\\)", "display": False},
|
206 |
-
{"left": "\\[", "right": "\\]", "display": True},
|
207 |
-
]
|
208 |
-
elif user_latex_option == "strict":
|
209 |
-
latex_delimiters_set = [
|
210 |
-
{"left": "$$", "right": "$$", "display": True},
|
211 |
-
{"left": "\\(", "right": "\\)", "display": False},
|
212 |
-
{"left": "\\[", "right": "\\]", "display": True},
|
213 |
-
]
|
214 |
-
elif user_latex_option == "all":
|
215 |
-
latex_delimiters_set = [
|
216 |
-
{"left": "$$", "right": "$$", "display": True},
|
217 |
-
{"left": "$", "right": "$", "display": False},
|
218 |
-
{"left": "\\(", "right": "\\)", "display": False},
|
219 |
-
{"left": "\\[", "right": "\\]", "display": True},
|
220 |
-
{"left": "\\begin{equation}", "right": "\\end{equation}", "display": True},
|
221 |
-
{"left": "\\begin{align}", "right": "\\end{align}", "display": True},
|
222 |
-
{"left": "\\begin{alignat}", "right": "\\end{alignat}", "display": True},
|
223 |
-
{"left": "\\begin{gather}", "right": "\\end{gather}", "display": True},
|
224 |
-
{"left": "\\begin{CD}", "right": "\\end{CD}", "display": True},
|
225 |
-
]
|
226 |
-
elif user_latex_option == "disabled":
|
227 |
-
latex_delimiters_set = []
|
228 |
-
else:
|
229 |
-
latex_delimiters_set = [
|
230 |
-
{"left": "$$", "right": "$$", "display": True},
|
231 |
-
{"left": "$", "right": "$", "display": False},
|
232 |
-
{"left": "\\(", "right": "\\)", "display": False},
|
233 |
-
{"left": "\\[", "right": "\\]", "display": True},
|
234 |
-
]
|
235 |
-
|
236 |
-
# 处理advance docs
|
237 |
advance_docs = defaultdict(lambda: defaultdict(dict))
|
238 |
advance_docs.update(config.get("advance_docs", {}))
|
239 |
-
|
240 |
-
|
241 |
def update_doc_config(two_column_pdf):
|
242 |
global advance_docs
|
243 |
advance_docs["pdf"]["two_column"] = two_column_pdf
|
244 |
|
245 |
logging.info(f"更新后的文件参数为:{advance_docs}")
|
246 |
|
247 |
-
|
248 |
-
# 处理gradio.launch参数
|
249 |
server_name = config.get("server_name", None)
|
250 |
server_port = config.get("server_port", None)
|
251 |
if server_name is None:
|
|
|
11 |
|
12 |
__all__ = [
|
13 |
"my_api_key",
|
|
|
14 |
"authflag",
|
15 |
"auth_list",
|
16 |
"dockerflag",
|
|
|
23 |
"server_name",
|
24 |
"server_port",
|
25 |
"share",
|
|
|
|
|
26 |
"hide_history_when_not_logged_in",
|
27 |
+
"default_chuanhu_assistant_model"
|
|
|
28 |
]
|
29 |
|
30 |
# 添加一个统一的config文件,避免文件过多造成的疑惑(优先级最低)
|
|
|
35 |
else:
|
36 |
config = {}
|
37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
lang_config = config.get("language", "auto")
|
39 |
language = os.environ.get("LANGUAGE", lang_config)
|
40 |
|
41 |
+
hide_history_when_not_logged_in = config.get("hide_history_when_not_logged_in", False)
|
|
|
|
|
|
|
|
|
42 |
|
43 |
if os.path.exists("api_key.txt"):
|
44 |
logging.info("检测到api_key.txt文件,正在进行迁移...")
|
|
|
52 |
logging.info("检测到auth.json文件,正在进行迁移...")
|
53 |
auth_list = []
|
54 |
with open("auth.json", "r", encoding='utf-8') as f:
|
55 |
+
auth = json.load(f)
|
56 |
+
for _ in auth:
|
57 |
+
if auth[_]["username"] and auth[_]["password"]:
|
58 |
+
auth_list.append((auth[_]["username"], auth[_]["password"]))
|
59 |
+
else:
|
60 |
+
logging.error("请检查auth.json文件中的用户名和密码!")
|
61 |
+
sys.exit(1)
|
62 |
config["users"] = auth_list
|
63 |
os.rename("auth.json", "auth(deprecated).json")
|
64 |
with open("config.json", "w", encoding='utf-8') as f:
|
65 |
json.dump(config, f, indent=4, ensure_ascii=False)
|
66 |
|
67 |
+
## 处理docker if we are running in Docker
|
68 |
dockerflag = config.get("dockerflag", False)
|
69 |
if os.environ.get("dockerrun") == "yes":
|
70 |
dockerflag = True
|
71 |
|
72 |
+
## 处理 api-key 以及 允许的用户列表
|
73 |
my_api_key = config.get("openai_api_key", "")
|
74 |
my_api_key = os.environ.get("OPENAI_API_KEY", my_api_key)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
|
76 |
xmchat_api_key = config.get("xmchat_api_key", "")
|
77 |
os.environ["XMCHAT_API_KEY"] = xmchat_api_key
|
|
|
81 |
minimax_group_id = config.get("minimax_group_id", "")
|
82 |
os.environ["MINIMAX_GROUP_ID"] = minimax_group_id
|
83 |
|
|
|
|
|
|
|
84 |
|
85 |
usage_limit = os.environ.get("USAGE_LIMIT", config.get("usage_limit", 120))
|
86 |
|
87 |
+
## 多账户机制
|
88 |
+
multi_api_key = config.get("multi_api_key", False) # 是否开启多账户机制
|
89 |
if multi_api_key:
|
90 |
api_key_list = config.get("api_key_list", [])
|
91 |
if len(api_key_list) == 0:
|
|
|
93 |
sys.exit(1)
|
94 |
shared.state.set_api_key_queue(api_key_list)
|
95 |
|
96 |
+
auth_list = config.get("users", []) # 实际上是使用者的列表
|
97 |
authflag = len(auth_list) > 0 # 是否开启认证的状态值,改为判断auth_list长度
|
98 |
|
99 |
# 处理自定义的api_host,优先读环境变量的配置,如果存在则自动装配
|
100 |
+
api_host = os.environ.get("OPENAI_API_BASE", config.get("openai_api_base", None))
|
|
|
101 |
if api_host is not None:
|
102 |
shared.state.set_api_host(api_host)
|
|
|
|
|
103 |
|
104 |
+
default_chuanhu_assistant_model = config.get("default_chuanhu_assistant_model", "gpt-3.5-turbo")
|
|
|
105 |
for x in ["GOOGLE_CSE_ID", "GOOGLE_API_KEY", "WOLFRAM_ALPHA_APPID", "SERPAPI_API_KEY"]:
|
106 |
if config.get(x, None) is not None:
|
107 |
os.environ[x] = config[x]
|
108 |
|
|
|
109 |
@contextmanager
|
110 |
+
def retrieve_openai_api(api_key = None):
|
111 |
old_api_key = os.environ.get("OPENAI_API_KEY", "")
|
112 |
if api_key is None:
|
113 |
os.environ["OPENAI_API_KEY"] = my_api_key
|
|
|
117 |
yield api_key
|
118 |
os.environ["OPENAI_API_KEY"] = old_api_key
|
119 |
|
120 |
+
## 处理log
|
|
|
121 |
log_level = config.get("log_level", "INFO")
|
122 |
logging.basicConfig(
|
123 |
level=log_level,
|
124 |
format="%(asctime)s [%(levelname)s] [%(filename)s:%(lineno)d] %(message)s",
|
125 |
)
|
126 |
|
127 |
+
## 处理代理:
|
128 |
+
http_proxy = config.get("http_proxy", "")
|
129 |
+
https_proxy = config.get("https_proxy", "")
|
130 |
+
http_proxy = os.environ.get("HTTP_PROXY", http_proxy)
|
131 |
+
https_proxy = os.environ.get("HTTPS_PROXY", https_proxy)
|
132 |
|
133 |
# 重置系统变量,在不需要设置的时候不设置环境变量,以免引起全局代理报错
|
134 |
os.environ["HTTP_PROXY"] = ""
|
135 |
os.environ["HTTPS_PROXY"] = ""
|
136 |
|
137 |
+
local_embedding = config.get("local_embedding", False) # 是否使用本地embedding
|
|
|
138 |
|
139 |
@contextmanager
|
140 |
def retrieve_proxy(proxy=None):
|
|
|
151 |
old_var = os.environ["HTTP_PROXY"], os.environ["HTTPS_PROXY"]
|
152 |
os.environ["HTTP_PROXY"] = http_proxy
|
153 |
os.environ["HTTPS_PROXY"] = https_proxy
|
154 |
+
yield http_proxy, https_proxy # return new proxy
|
155 |
|
156 |
# return old proxy
|
157 |
os.environ["HTTP_PROXY"], os.environ["HTTPS_PROXY"] = old_var
|
158 |
|
159 |
|
160 |
+
## 处理advance docs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
161 |
advance_docs = defaultdict(lambda: defaultdict(dict))
|
162 |
advance_docs.update(config.get("advance_docs", {}))
|
|
|
|
|
163 |
def update_doc_config(two_column_pdf):
|
164 |
global advance_docs
|
165 |
advance_docs["pdf"]["two_column"] = two_column_pdf
|
166 |
|
167 |
logging.info(f"更新后的文件参数为:{advance_docs}")
|
168 |
|
169 |
+
## 处理gradio.launch参数
|
|
|
170 |
server_name = config.get("server_name", None)
|
171 |
server_port = config.get("server_port", None)
|
172 |
if server_name is None:
|
modules/index_func.py
CHANGED
@@ -47,12 +47,11 @@ def get_documents(file_src):
|
|
47 |
pdftext = parse_pdf(filepath, two_column).text
|
48 |
except:
|
49 |
pdftext = ""
|
50 |
-
with open(filepath, "rb") as pdfFileObj:
|
51 |
pdfReader = PyPDF2.PdfReader(pdfFileObj)
|
52 |
for page in tqdm(pdfReader.pages):
|
53 |
pdftext += page.extract_text()
|
54 |
-
texts = [Document(page_content=pdftext,
|
55 |
-
metadata={"source": filepath})]
|
56 |
elif file_type == ".docx":
|
57 |
logging.debug("Loading Word...")
|
58 |
from langchain.document_loaders import UnstructuredWordDocumentLoader
|
@@ -73,8 +72,7 @@ def get_documents(file_src):
|
|
73 |
text_list = excel_to_string(filepath)
|
74 |
texts = []
|
75 |
for elem in text_list:
|
76 |
-
texts.append(Document(page_content=elem,
|
77 |
-
metadata={"source": filepath}))
|
78 |
else:
|
79 |
logging.debug("Loading text file...")
|
80 |
from langchain.document_loaders import TextLoader
|
@@ -117,16 +115,10 @@ def construct_index(
|
|
117 |
index_path = f"./index/{index_name}"
|
118 |
if local_embedding:
|
119 |
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
|
120 |
-
embeddings = HuggingFaceEmbeddings(
|
121 |
-
model_name="sentence-transformers/distiluse-base-multilingual-cased-v2")
|
122 |
else:
|
123 |
from langchain.embeddings import OpenAIEmbeddings
|
124 |
-
|
125 |
-
embeddings = OpenAIEmbeddings(openai_api_base=os.environ.get(
|
126 |
-
"OPENAI_API_BASE", None), openai_api_key=os.environ.get("OPENAI_EMBEDDING_API_KEY", api_key))
|
127 |
-
else:
|
128 |
-
embeddings = OpenAIEmbeddings(deployment=os.environ["AZURE_EMBEDDING_DEPLOYMENT_NAME"], openai_api_key=os.environ["AZURE_OPENAI_API_KEY"],
|
129 |
-
model=os.environ["AZURE_EMBEDDING_MODEL_NAME"], openai_api_base=os.environ["AZURE_OPENAI_API_BASE_URL"], openai_api_type="azure")
|
130 |
if os.path.exists(index_path):
|
131 |
logging.info("找到了缓存的索引文件,加载中……")
|
132 |
return FAISS.load_local(index_path, embeddings)
|
|
|
47 |
pdftext = parse_pdf(filepath, two_column).text
|
48 |
except:
|
49 |
pdftext = ""
|
50 |
+
with open(filepath, "rb", encoding="utf-8") as pdfFileObj:
|
51 |
pdfReader = PyPDF2.PdfReader(pdfFileObj)
|
52 |
for page in tqdm(pdfReader.pages):
|
53 |
pdftext += page.extract_text()
|
54 |
+
texts = [Document(page_content=pdftext, metadata={"source": filepath})]
|
|
|
55 |
elif file_type == ".docx":
|
56 |
logging.debug("Loading Word...")
|
57 |
from langchain.document_loaders import UnstructuredWordDocumentLoader
|
|
|
72 |
text_list = excel_to_string(filepath)
|
73 |
texts = []
|
74 |
for elem in text_list:
|
75 |
+
texts.append(Document(page_content=elem, metadata={"source": filepath}))
|
|
|
76 |
else:
|
77 |
logging.debug("Loading text file...")
|
78 |
from langchain.document_loaders import TextLoader
|
|
|
115 |
index_path = f"./index/{index_name}"
|
116 |
if local_embedding:
|
117 |
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
|
118 |
+
embeddings = HuggingFaceEmbeddings(model_name = "sentence-transformers/distiluse-base-multilingual-cased-v2")
|
|
|
119 |
else:
|
120 |
from langchain.embeddings import OpenAIEmbeddings
|
121 |
+
embeddings = OpenAIEmbeddings(openai_api_base=os.environ.get("OPENAI_API_BASE", None), openai_api_key=os.environ.get("OPENAI_EMBEDDING_API_KEY", api_key))
|
|
|
|
|
|
|
|
|
|
|
122 |
if os.path.exists(index_path):
|
123 |
logging.info("找到了缓存的索引文件,加载中……")
|
124 |
return FAISS.load_local(index_path, embeddings)
|
modules/llama_func.py
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import logging
|
3 |
+
|
4 |
+
from llama_index import download_loader
|
5 |
+
from llama_index import (
|
6 |
+
Document,
|
7 |
+
LLMPredictor,
|
8 |
+
PromptHelper,
|
9 |
+
QuestionAnswerPrompt,
|
10 |
+
RefinePrompt,
|
11 |
+
)
|
12 |
+
import colorama
|
13 |
+
import PyPDF2
|
14 |
+
from tqdm import tqdm
|
15 |
+
|
16 |
+
from modules.presets import *
|
17 |
+
from modules.utils import *
|
18 |
+
from modules.config import local_embedding
|
19 |
+
|
20 |
+
|
21 |
+
def get_index_name(file_src):
|
22 |
+
file_paths = [x.name for x in file_src]
|
23 |
+
file_paths.sort(key=lambda x: os.path.basename(x))
|
24 |
+
|
25 |
+
md5_hash = hashlib.md5()
|
26 |
+
for file_path in file_paths:
|
27 |
+
with open(file_path, "rb") as f:
|
28 |
+
while chunk := f.read(8192):
|
29 |
+
md5_hash.update(chunk)
|
30 |
+
|
31 |
+
return md5_hash.hexdigest()
|
32 |
+
|
33 |
+
|
34 |
+
def block_split(text):
|
35 |
+
blocks = []
|
36 |
+
while len(text) > 0:
|
37 |
+
blocks.append(Document(text[:1000]))
|
38 |
+
text = text[1000:]
|
39 |
+
return blocks
|
40 |
+
|
41 |
+
|
42 |
+
def get_documents(file_src):
|
43 |
+
documents = []
|
44 |
+
logging.debug("Loading documents...")
|
45 |
+
logging.debug(f"file_src: {file_src}")
|
46 |
+
for file in file_src:
|
47 |
+
filepath = file.name
|
48 |
+
filename = os.path.basename(filepath)
|
49 |
+
file_type = os.path.splitext(filepath)[1]
|
50 |
+
logging.info(f"loading file: {filename}")
|
51 |
+
try:
|
52 |
+
if file_type == ".pdf":
|
53 |
+
logging.debug("Loading PDF...")
|
54 |
+
try:
|
55 |
+
from modules.pdf_func import parse_pdf
|
56 |
+
from modules.config import advance_docs
|
57 |
+
|
58 |
+
two_column = advance_docs["pdf"].get("two_column", False)
|
59 |
+
pdftext = parse_pdf(filepath, two_column).text
|
60 |
+
except:
|
61 |
+
pdftext = ""
|
62 |
+
with open(filepath, "rb") as pdfFileObj:
|
63 |
+
pdfReader = PyPDF2.PdfReader(pdfFileObj)
|
64 |
+
for page in tqdm(pdfReader.pages):
|
65 |
+
pdftext += page.extract_text()
|
66 |
+
text_raw = pdftext
|
67 |
+
elif file_type == ".docx":
|
68 |
+
logging.debug("Loading Word...")
|
69 |
+
DocxReader = download_loader("DocxReader")
|
70 |
+
loader = DocxReader()
|
71 |
+
text_raw = loader.load_data(file=filepath)[0].text
|
72 |
+
elif file_type == ".epub":
|
73 |
+
logging.debug("Loading EPUB...")
|
74 |
+
EpubReader = download_loader("EpubReader")
|
75 |
+
loader = EpubReader()
|
76 |
+
text_raw = loader.load_data(file=filepath)[0].text
|
77 |
+
elif file_type == ".xlsx":
|
78 |
+
logging.debug("Loading Excel...")
|
79 |
+
text_list = excel_to_string(filepath)
|
80 |
+
for elem in text_list:
|
81 |
+
documents.append(Document(elem))
|
82 |
+
continue
|
83 |
+
else:
|
84 |
+
logging.debug("Loading text file...")
|
85 |
+
with open(filepath, "r", encoding="utf-8") as f:
|
86 |
+
text_raw = f.read()
|
87 |
+
except Exception as e:
|
88 |
+
logging.error(f"Error loading file: {filename}")
|
89 |
+
pass
|
90 |
+
text = add_space(text_raw)
|
91 |
+
# text = block_split(text)
|
92 |
+
# documents += text
|
93 |
+
documents += [Document(text)]
|
94 |
+
logging.debug("Documents loaded.")
|
95 |
+
return documents
|
96 |
+
|
97 |
+
|
98 |
+
def construct_index(
|
99 |
+
api_key,
|
100 |
+
file_src,
|
101 |
+
max_input_size=4096,
|
102 |
+
num_outputs=5,
|
103 |
+
max_chunk_overlap=20,
|
104 |
+
chunk_size_limit=600,
|
105 |
+
embedding_limit=None,
|
106 |
+
separator=" ",
|
107 |
+
):
|
108 |
+
from langchain.chat_models import ChatOpenAI
|
109 |
+
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
|
110 |
+
from llama_index import GPTSimpleVectorIndex, ServiceContext, LangchainEmbedding, OpenAIEmbedding
|
111 |
+
|
112 |
+
if api_key:
|
113 |
+
os.environ["OPENAI_API_KEY"] = api_key
|
114 |
+
else:
|
115 |
+
# 由于一个依赖的愚蠢的设计,这里必须要有一个API KEY
|
116 |
+
os.environ["OPENAI_API_KEY"] = "sk-xxxxxxx"
|
117 |
+
chunk_size_limit = None if chunk_size_limit == 0 else chunk_size_limit
|
118 |
+
embedding_limit = None if embedding_limit == 0 else embedding_limit
|
119 |
+
separator = " " if separator == "" else separator
|
120 |
+
|
121 |
+
prompt_helper = PromptHelper(
|
122 |
+
max_input_size=max_input_size,
|
123 |
+
num_output=num_outputs,
|
124 |
+
max_chunk_overlap=max_chunk_overlap,
|
125 |
+
embedding_limit=embedding_limit,
|
126 |
+
chunk_size_limit=600,
|
127 |
+
separator=separator,
|
128 |
+
)
|
129 |
+
index_name = get_index_name(file_src)
|
130 |
+
if os.path.exists(f"./index/{index_name}.json"):
|
131 |
+
logging.info("找到了缓存的索引文件,加载中……")
|
132 |
+
return GPTSimpleVectorIndex.load_from_disk(f"./index/{index_name}.json")
|
133 |
+
else:
|
134 |
+
try:
|
135 |
+
documents = get_documents(file_src)
|
136 |
+
if local_embedding:
|
137 |
+
embed_model = LangchainEmbedding(HuggingFaceEmbeddings(model_name = "sentence-transformers/distiluse-base-multilingual-cased-v2"))
|
138 |
+
else:
|
139 |
+
embed_model = OpenAIEmbedding()
|
140 |
+
logging.info("构建索引中……")
|
141 |
+
with retrieve_proxy():
|
142 |
+
service_context = ServiceContext.from_defaults(
|
143 |
+
prompt_helper=prompt_helper,
|
144 |
+
chunk_size_limit=chunk_size_limit,
|
145 |
+
embed_model=embed_model,
|
146 |
+
)
|
147 |
+
index = GPTSimpleVectorIndex.from_documents(
|
148 |
+
documents, service_context=service_context
|
149 |
+
)
|
150 |
+
logging.debug("索引构建完成!")
|
151 |
+
os.makedirs("./index", exist_ok=True)
|
152 |
+
index.save_to_disk(f"./index/{index_name}.json")
|
153 |
+
logging.debug("索引已保存至本地!")
|
154 |
+
return index
|
155 |
+
|
156 |
+
except Exception as e:
|
157 |
+
logging.error("索引构建失败!", e)
|
158 |
+
print(e)
|
159 |
+
return None
|
160 |
+
|
161 |
+
|
162 |
+
def add_space(text):
|
163 |
+
punctuations = {",": ", ", "。": "。 ", "?": "? ", "!": "! ", ":": ": ", ";": "; "}
|
164 |
+
for cn_punc, en_punc in punctuations.items():
|
165 |
+
text = text.replace(cn_punc, en_punc)
|
166 |
+
return text
|
modules/models.py
ADDED
@@ -0,0 +1,625 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
from typing import TYPE_CHECKING, List
|
3 |
+
|
4 |
+
import logging
|
5 |
+
import json
|
6 |
+
import commentjson as cjson
|
7 |
+
import os
|
8 |
+
import sys
|
9 |
+
import requests
|
10 |
+
import urllib3
|
11 |
+
import platform
|
12 |
+
import base64
|
13 |
+
from io import BytesIO
|
14 |
+
from PIL import Image
|
15 |
+
|
16 |
+
from tqdm import tqdm
|
17 |
+
import colorama
|
18 |
+
from duckduckgo_search import ddg
|
19 |
+
import asyncio
|
20 |
+
import aiohttp
|
21 |
+
from enum import Enum
|
22 |
+
import uuid
|
23 |
+
|
24 |
+
from .presets import *
|
25 |
+
from .llama_func import *
|
26 |
+
from .utils import *
|
27 |
+
from . import shared
|
28 |
+
from .config import retrieve_proxy
|
29 |
+
from modules import config
|
30 |
+
from .base_model import BaseLLMModel, ModelType
|
31 |
+
|
32 |
+
|
33 |
+
class OpenAIClient(BaseLLMModel):
|
34 |
+
def __init__(
|
35 |
+
self,
|
36 |
+
model_name,
|
37 |
+
api_key,
|
38 |
+
system_prompt=INITIAL_SYSTEM_PROMPT,
|
39 |
+
temperature=1.0,
|
40 |
+
top_p=1.0,
|
41 |
+
) -> None:
|
42 |
+
super().__init__(
|
43 |
+
model_name=model_name,
|
44 |
+
temperature=temperature,
|
45 |
+
top_p=top_p,
|
46 |
+
system_prompt=system_prompt,
|
47 |
+
)
|
48 |
+
self.api_key = api_key
|
49 |
+
self.need_api_key = True
|
50 |
+
self._refresh_header()
|
51 |
+
|
52 |
+
def get_answer_stream_iter(self):
|
53 |
+
response = self._get_response(stream=True)
|
54 |
+
if response is not None:
|
55 |
+
iter = self._decode_chat_response(response)
|
56 |
+
partial_text = ""
|
57 |
+
for i in iter:
|
58 |
+
partial_text += i
|
59 |
+
yield partial_text
|
60 |
+
else:
|
61 |
+
yield STANDARD_ERROR_MSG + GENERAL_ERROR_MSG
|
62 |
+
|
63 |
+
def get_answer_at_once(self):
|
64 |
+
response = self._get_response()
|
65 |
+
response = json.loads(response.text)
|
66 |
+
content = response["choices"][0]["message"]["content"]
|
67 |
+
total_token_count = response["usage"]["total_tokens"]
|
68 |
+
return content, total_token_count
|
69 |
+
|
70 |
+
def count_token(self, user_input):
|
71 |
+
input_token_count = count_token(construct_user(user_input))
|
72 |
+
if self.system_prompt is not None and len(self.all_token_counts) == 0:
|
73 |
+
system_prompt_token_count = count_token(
|
74 |
+
construct_system(self.system_prompt)
|
75 |
+
)
|
76 |
+
return input_token_count + system_prompt_token_count
|
77 |
+
return input_token_count
|
78 |
+
|
79 |
+
def billing_info(self):
|
80 |
+
try:
|
81 |
+
curr_time = datetime.datetime.now()
|
82 |
+
last_day_of_month = get_last_day_of_month(
|
83 |
+
curr_time).strftime("%Y-%m-%d")
|
84 |
+
first_day_of_month = curr_time.replace(day=1).strftime("%Y-%m-%d")
|
85 |
+
usage_url = f"{shared.state.usage_api_url}?start_date={first_day_of_month}&end_date={last_day_of_month}"
|
86 |
+
try:
|
87 |
+
usage_data = self._get_billing_data(usage_url)
|
88 |
+
except Exception as e:
|
89 |
+
logging.error(f"获取API使用情况失败:" + str(e))
|
90 |
+
return i18n("**获取API使用情况失败**")
|
91 |
+
rounded_usage = "{:.5f}".format(usage_data["total_usage"] / 100)
|
92 |
+
return i18n("**本月使用金额** ") + f"\u3000 ${rounded_usage}"
|
93 |
+
except requests.exceptions.ConnectTimeout:
|
94 |
+
status_text = (
|
95 |
+
STANDARD_ERROR_MSG + CONNECTION_TIMEOUT_MSG + ERROR_RETRIEVE_MSG
|
96 |
+
)
|
97 |
+
return status_text
|
98 |
+
except requests.exceptions.ReadTimeout:
|
99 |
+
status_text = STANDARD_ERROR_MSG + READ_TIMEOUT_MSG + ERROR_RETRIEVE_MSG
|
100 |
+
return status_text
|
101 |
+
except Exception as e:
|
102 |
+
import traceback
|
103 |
+
traceback.print_exc()
|
104 |
+
logging.error(i18n("获取API使用情况失败:") + str(e))
|
105 |
+
return STANDARD_ERROR_MSG + ERROR_RETRIEVE_MSG
|
106 |
+
|
107 |
+
def set_token_upper_limit(self, new_upper_limit):
|
108 |
+
pass
|
109 |
+
|
110 |
+
@shared.state.switching_api_key # 在不开启多账号模式的时候,这个装饰器不会起作用
|
111 |
+
def _get_response(self, stream=False):
|
112 |
+
openai_api_key = self.api_key
|
113 |
+
system_prompt = self.system_prompt
|
114 |
+
history = self.history
|
115 |
+
logging.debug(colorama.Fore.YELLOW +
|
116 |
+
f"{history}" + colorama.Fore.RESET)
|
117 |
+
headers = {
|
118 |
+
"Content-Type": "application/json",
|
119 |
+
"Authorization": f"Bearer {openai_api_key}",
|
120 |
+
}
|
121 |
+
|
122 |
+
if system_prompt is not None:
|
123 |
+
history = [construct_system(system_prompt), *history]
|
124 |
+
|
125 |
+
payload = {
|
126 |
+
"model": self.model_name,
|
127 |
+
"messages": history,
|
128 |
+
"temperature": self.temperature,
|
129 |
+
"top_p": self.top_p,
|
130 |
+
"n": self.n_choices,
|
131 |
+
"stream": stream,
|
132 |
+
"presence_penalty": self.presence_penalty,
|
133 |
+
"frequency_penalty": self.frequency_penalty,
|
134 |
+
}
|
135 |
+
|
136 |
+
if self.max_generation_token is not None:
|
137 |
+
payload["max_tokens"] = self.max_generation_token
|
138 |
+
if self.stop_sequence is not None:
|
139 |
+
payload["stop"] = self.stop_sequence
|
140 |
+
if self.logit_bias is not None:
|
141 |
+
payload["logit_bias"] = self.logit_bias
|
142 |
+
if self.user_identifier is not None:
|
143 |
+
payload["user"] = self.user_identifier
|
144 |
+
|
145 |
+
if stream:
|
146 |
+
timeout = TIMEOUT_STREAMING
|
147 |
+
else:
|
148 |
+
timeout = TIMEOUT_ALL
|
149 |
+
|
150 |
+
# 如果有自定义的api-host,使用自定义host发送请求,否则使用默认设置发送请求
|
151 |
+
if shared.state.completion_url != COMPLETION_URL:
|
152 |
+
logging.info(f"使用自定义API URL: {shared.state.completion_url}")
|
153 |
+
|
154 |
+
with retrieve_proxy():
|
155 |
+
try:
|
156 |
+
response = requests.post(
|
157 |
+
shared.state.completion_url,
|
158 |
+
headers=headers,
|
159 |
+
json=payload,
|
160 |
+
stream=stream,
|
161 |
+
timeout=timeout,
|
162 |
+
)
|
163 |
+
except:
|
164 |
+
return None
|
165 |
+
return response
|
166 |
+
|
167 |
+
def _refresh_header(self):
|
168 |
+
self.headers = {
|
169 |
+
"Content-Type": "application/json",
|
170 |
+
"Authorization": f"Bearer {self.api_key}",
|
171 |
+
}
|
172 |
+
|
173 |
+
def _get_billing_data(self, billing_url):
|
174 |
+
with retrieve_proxy():
|
175 |
+
response = requests.get(
|
176 |
+
billing_url,
|
177 |
+
headers=self.headers,
|
178 |
+
timeout=TIMEOUT_ALL,
|
179 |
+
)
|
180 |
+
|
181 |
+
if response.status_code == 200:
|
182 |
+
data = response.json()
|
183 |
+
return data
|
184 |
+
else:
|
185 |
+
raise Exception(
|
186 |
+
f"API request failed with status code {response.status_code}: {response.text}"
|
187 |
+
)
|
188 |
+
|
189 |
+
def _decode_chat_response(self, response):
|
190 |
+
error_msg = ""
|
191 |
+
for chunk in response.iter_lines():
|
192 |
+
if chunk:
|
193 |
+
chunk = chunk.decode()
|
194 |
+
chunk_length = len(chunk)
|
195 |
+
try:
|
196 |
+
chunk = json.loads(chunk[6:])
|
197 |
+
except json.JSONDecodeError:
|
198 |
+
print(i18n("JSON解析错误,收到的内容: ") + f"{chunk}")
|
199 |
+
error_msg += chunk
|
200 |
+
continue
|
201 |
+
if chunk_length > 6 and "delta" in chunk["choices"][0]:
|
202 |
+
if chunk["choices"][0]["finish_reason"] == "stop":
|
203 |
+
break
|
204 |
+
try:
|
205 |
+
yield chunk["choices"][0]["delta"]["content"]
|
206 |
+
except Exception as e:
|
207 |
+
# logging.error(f"Error: {e}")
|
208 |
+
continue
|
209 |
+
if error_msg:
|
210 |
+
raise Exception(error_msg)
|
211 |
+
|
212 |
+
def set_key(self, new_access_key):
|
213 |
+
ret = super().set_key(new_access_key)
|
214 |
+
self._refresh_header()
|
215 |
+
return ret
|
216 |
+
|
217 |
+
|
218 |
+
class ChatGLM_Client(BaseLLMModel):
|
219 |
+
def __init__(self, model_name) -> None:
|
220 |
+
super().__init__(model_name=model_name)
|
221 |
+
from transformers import AutoTokenizer, AutoModel
|
222 |
+
import torch
|
223 |
+
global CHATGLM_TOKENIZER, CHATGLM_MODEL
|
224 |
+
if CHATGLM_TOKENIZER is None or CHATGLM_MODEL is None:
|
225 |
+
system_name = platform.system()
|
226 |
+
model_path = None
|
227 |
+
if os.path.exists("models"):
|
228 |
+
model_dirs = os.listdir("models")
|
229 |
+
if model_name in model_dirs:
|
230 |
+
model_path = f"models/{model_name}"
|
231 |
+
if model_path is not None:
|
232 |
+
model_source = model_path
|
233 |
+
else:
|
234 |
+
model_source = f"THUDM/{model_name}"
|
235 |
+
CHATGLM_TOKENIZER = AutoTokenizer.from_pretrained(
|
236 |
+
model_source, trust_remote_code=True
|
237 |
+
)
|
238 |
+
quantified = False
|
239 |
+
if "int4" in model_name:
|
240 |
+
quantified = True
|
241 |
+
model = AutoModel.from_pretrained(
|
242 |
+
model_source, trust_remote_code=True
|
243 |
+
)
|
244 |
+
if torch.cuda.is_available():
|
245 |
+
# run on CUDA
|
246 |
+
logging.info("CUDA is available, using CUDA")
|
247 |
+
model = model.half().cuda()
|
248 |
+
# mps加速还存在一些问题,暂时不使用
|
249 |
+
elif system_name == "Darwin" and model_path is not None and not quantified:
|
250 |
+
logging.info("Running on macOS, using MPS")
|
251 |
+
# running on macOS and model already downloaded
|
252 |
+
model = model.half().to("mps")
|
253 |
+
else:
|
254 |
+
logging.info("GPU is not available, using CPU")
|
255 |
+
model = model.float()
|
256 |
+
model = model.eval()
|
257 |
+
CHATGLM_MODEL = model
|
258 |
+
|
259 |
+
def _get_glm_style_input(self):
|
260 |
+
history = [x["content"] for x in self.history]
|
261 |
+
query = history.pop()
|
262 |
+
logging.debug(colorama.Fore.YELLOW +
|
263 |
+
f"{history}" + colorama.Fore.RESET)
|
264 |
+
assert (
|
265 |
+
len(history) % 2 == 0
|
266 |
+
), f"History should be even length. current history is: {history}"
|
267 |
+
history = [[history[i], history[i + 1]]
|
268 |
+
for i in range(0, len(history), 2)]
|
269 |
+
return history, query
|
270 |
+
|
271 |
+
def get_answer_at_once(self):
|
272 |
+
history, query = self._get_glm_style_input()
|
273 |
+
response, _ = CHATGLM_MODEL.chat(
|
274 |
+
CHATGLM_TOKENIZER, query, history=history)
|
275 |
+
return response, len(response)
|
276 |
+
|
277 |
+
def get_answer_stream_iter(self):
|
278 |
+
history, query = self._get_glm_style_input()
|
279 |
+
for response, history in CHATGLM_MODEL.stream_chat(
|
280 |
+
CHATGLM_TOKENIZER,
|
281 |
+
query,
|
282 |
+
history,
|
283 |
+
max_length=self.token_upper_limit,
|
284 |
+
top_p=self.top_p,
|
285 |
+
temperature=self.temperature,
|
286 |
+
):
|
287 |
+
yield response
|
288 |
+
|
289 |
+
|
290 |
+
class LLaMA_Client(BaseLLMModel):
|
291 |
+
def __init__(
|
292 |
+
self,
|
293 |
+
model_name,
|
294 |
+
lora_path=None,
|
295 |
+
) -> None:
|
296 |
+
super().__init__(model_name=model_name)
|
297 |
+
from lmflow.datasets.dataset import Dataset
|
298 |
+
from lmflow.pipeline.auto_pipeline import AutoPipeline
|
299 |
+
from lmflow.models.auto_model import AutoModel
|
300 |
+
from lmflow.args import ModelArguments, DatasetArguments, InferencerArguments
|
301 |
+
|
302 |
+
self.max_generation_token = 1000
|
303 |
+
self.end_string = "\n\n"
|
304 |
+
# We don't need input data
|
305 |
+
data_args = DatasetArguments(dataset_path=None)
|
306 |
+
self.dataset = Dataset(data_args)
|
307 |
+
self.system_prompt = ""
|
308 |
+
|
309 |
+
global LLAMA_MODEL, LLAMA_INFERENCER
|
310 |
+
if LLAMA_MODEL is None or LLAMA_INFERENCER is None:
|
311 |
+
model_path = None
|
312 |
+
if os.path.exists("models"):
|
313 |
+
model_dirs = os.listdir("models")
|
314 |
+
if model_name in model_dirs:
|
315 |
+
model_path = f"models/{model_name}"
|
316 |
+
if model_path is not None:
|
317 |
+
model_source = model_path
|
318 |
+
else:
|
319 |
+
model_source = f"decapoda-research/{model_name}"
|
320 |
+
# raise Exception(f"models目录下没有这个模型: {model_name}")
|
321 |
+
if lora_path is not None:
|
322 |
+
lora_path = f"lora/{lora_path}"
|
323 |
+
model_args = ModelArguments(model_name_or_path=model_source, lora_model_path=lora_path, model_type=None, config_overrides=None, config_name=None, tokenizer_name=None, cache_dir=None,
|
324 |
+
use_fast_tokenizer=True, model_revision='main', use_auth_token=False, torch_dtype=None, use_lora=False, lora_r=8, lora_alpha=32, lora_dropout=0.1, use_ram_optimized_load=True)
|
325 |
+
pipeline_args = InferencerArguments(
|
326 |
+
local_rank=0, random_seed=1, deepspeed='configs/ds_config_chatbot.json', mixed_precision='bf16')
|
327 |
+
|
328 |
+
with open(pipeline_args.deepspeed, "r") as f:
|
329 |
+
ds_config = json.load(f)
|
330 |
+
LLAMA_MODEL = AutoModel.get_model(
|
331 |
+
model_args,
|
332 |
+
tune_strategy="none",
|
333 |
+
ds_config=ds_config,
|
334 |
+
)
|
335 |
+
LLAMA_INFERENCER = AutoPipeline.get_pipeline(
|
336 |
+
pipeline_name="inferencer",
|
337 |
+
model_args=model_args,
|
338 |
+
data_args=data_args,
|
339 |
+
pipeline_args=pipeline_args,
|
340 |
+
)
|
341 |
+
|
342 |
+
def _get_llama_style_input(self):
|
343 |
+
history = []
|
344 |
+
instruction = ""
|
345 |
+
if self.system_prompt:
|
346 |
+
instruction = (f"Instruction: {self.system_prompt}\n")
|
347 |
+
for x in self.history:
|
348 |
+
if x["role"] == "user":
|
349 |
+
history.append(f"{instruction}Input: {x['content']}")
|
350 |
+
else:
|
351 |
+
history.append(f"Output: {x['content']}")
|
352 |
+
context = "\n\n".join(history)
|
353 |
+
context += "\n\nOutput: "
|
354 |
+
return context
|
355 |
+
|
356 |
+
def get_answer_at_once(self):
|
357 |
+
context = self._get_llama_style_input()
|
358 |
+
|
359 |
+
input_dataset = self.dataset.from_dict(
|
360 |
+
{"type": "text_only", "instances": [{"text": context}]}
|
361 |
+
)
|
362 |
+
|
363 |
+
output_dataset = LLAMA_INFERENCER.inference(
|
364 |
+
model=LLAMA_MODEL,
|
365 |
+
dataset=input_dataset,
|
366 |
+
max_new_tokens=self.max_generation_token,
|
367 |
+
temperature=self.temperature,
|
368 |
+
)
|
369 |
+
|
370 |
+
response = output_dataset.to_dict()["instances"][0]["text"]
|
371 |
+
return response, len(response)
|
372 |
+
|
373 |
+
def get_answer_stream_iter(self):
|
374 |
+
context = self._get_llama_style_input()
|
375 |
+
partial_text = ""
|
376 |
+
step = 1
|
377 |
+
for _ in range(0, self.max_generation_token, step):
|
378 |
+
input_dataset = self.dataset.from_dict(
|
379 |
+
{"type": "text_only", "instances": [
|
380 |
+
{"text": context + partial_text}]}
|
381 |
+
)
|
382 |
+
output_dataset = LLAMA_INFERENCER.inference(
|
383 |
+
model=LLAMA_MODEL,
|
384 |
+
dataset=input_dataset,
|
385 |
+
max_new_tokens=step,
|
386 |
+
temperature=self.temperature,
|
387 |
+
)
|
388 |
+
response = output_dataset.to_dict()["instances"][0]["text"]
|
389 |
+
if response == "" or response == self.end_string:
|
390 |
+
break
|
391 |
+
partial_text += response
|
392 |
+
yield partial_text
|
393 |
+
|
394 |
+
|
395 |
+
class XMChat(BaseLLMModel):
|
396 |
+
def __init__(self, api_key):
|
397 |
+
super().__init__(model_name="xmchat")
|
398 |
+
self.api_key = api_key
|
399 |
+
self.session_id = None
|
400 |
+
self.reset()
|
401 |
+
self.image_bytes = None
|
402 |
+
self.image_path = None
|
403 |
+
self.xm_history = []
|
404 |
+
self.url = "https://xmbot.net/web"
|
405 |
+
self.last_conv_id = None
|
406 |
+
|
407 |
+
def reset(self):
|
408 |
+
self.session_id = str(uuid.uuid4())
|
409 |
+
self.last_conv_id = None
|
410 |
+
return [], "已重置"
|
411 |
+
|
412 |
+
def image_to_base64(self, image_path):
|
413 |
+
# 打开并加载图片
|
414 |
+
img = Image.open(image_path)
|
415 |
+
|
416 |
+
# 获取图片的宽度和高度
|
417 |
+
width, height = img.size
|
418 |
+
|
419 |
+
# 计算压缩比例,以确保最长边小于4096像素
|
420 |
+
max_dimension = 2048
|
421 |
+
scale_ratio = min(max_dimension / width, max_dimension / height)
|
422 |
+
|
423 |
+
if scale_ratio < 1:
|
424 |
+
# 按压缩比例调整图片大小
|
425 |
+
new_width = int(width * scale_ratio)
|
426 |
+
new_height = int(height * scale_ratio)
|
427 |
+
img = img.resize((new_width, new_height), Image.ANTIALIAS)
|
428 |
+
|
429 |
+
# 将图片转换为jpg格式的二进制数据
|
430 |
+
buffer = BytesIO()
|
431 |
+
if img.mode == "RGBA":
|
432 |
+
img = img.convert("RGB")
|
433 |
+
img.save(buffer, format='JPEG')
|
434 |
+
binary_image = buffer.getvalue()
|
435 |
+
|
436 |
+
# 对二进制数据进行Base64编码
|
437 |
+
base64_image = base64.b64encode(binary_image).decode('utf-8')
|
438 |
+
|
439 |
+
return base64_image
|
440 |
+
|
441 |
+
def try_read_image(self, filepath):
|
442 |
+
def is_image_file(filepath):
|
443 |
+
# 判断文件是否为图片
|
444 |
+
valid_image_extensions = [".jpg", ".jpeg", ".png", ".bmp", ".gif", ".tiff"]
|
445 |
+
file_extension = os.path.splitext(filepath)[1].lower()
|
446 |
+
return file_extension in valid_image_extensions
|
447 |
+
|
448 |
+
if is_image_file(filepath):
|
449 |
+
logging.info(f"读取图片文件: {filepath}")
|
450 |
+
self.image_bytes = self.image_to_base64(filepath)
|
451 |
+
self.image_path = filepath
|
452 |
+
else:
|
453 |
+
self.image_bytes = None
|
454 |
+
self.image_path = None
|
455 |
+
|
456 |
+
def like(self):
|
457 |
+
if self.last_conv_id is None:
|
458 |
+
return "点赞失败,你还没发送过消息"
|
459 |
+
data = {
|
460 |
+
"uuid": self.last_conv_id,
|
461 |
+
"appraise": "good"
|
462 |
+
}
|
463 |
+
response = requests.post(self.url, json=data)
|
464 |
+
return "👍点赞成功,,感谢反馈~"
|
465 |
+
|
466 |
+
def dislike(self):
|
467 |
+
if self.last_conv_id is None:
|
468 |
+
return "点踩失败,你还没发送过消息"
|
469 |
+
data = {
|
470 |
+
"uuid": self.last_conv_id,
|
471 |
+
"appraise": "bad"
|
472 |
+
}
|
473 |
+
response = requests.post(self.url, json=data)
|
474 |
+
return "👎点踩成功,感谢反馈~"
|
475 |
+
|
476 |
+
def prepare_inputs(self, real_inputs, use_websearch, files, reply_language, chatbot):
|
477 |
+
fake_inputs = real_inputs
|
478 |
+
display_append = ""
|
479 |
+
limited_context = False
|
480 |
+
return limited_context, fake_inputs, display_append, real_inputs, chatbot
|
481 |
+
|
482 |
+
def handle_file_upload(self, files, chatbot):
|
483 |
+
"""if the model accepts multi modal input, implement this function"""
|
484 |
+
if files:
|
485 |
+
for file in files:
|
486 |
+
if file.name:
|
487 |
+
logging.info(f"尝试读取图像: {file.name}")
|
488 |
+
self.try_read_image(file.name)
|
489 |
+
if self.image_path is not None:
|
490 |
+
chatbot = chatbot + [((self.image_path,), None)]
|
491 |
+
if self.image_bytes is not None:
|
492 |
+
logging.info("使用图片作为输入")
|
493 |
+
# XMChat的一轮对话中实际上只能处理一张图片
|
494 |
+
self.reset()
|
495 |
+
conv_id = str(uuid.uuid4())
|
496 |
+
data = {
|
497 |
+
"user_id": self.api_key,
|
498 |
+
"session_id": self.session_id,
|
499 |
+
"uuid": conv_id,
|
500 |
+
"data_type": "imgbase64",
|
501 |
+
"data": self.image_bytes
|
502 |
+
}
|
503 |
+
response = requests.post(self.url, json=data)
|
504 |
+
response = json.loads(response.text)
|
505 |
+
logging.info(f"图片回复: {response['data']}")
|
506 |
+
return None, chatbot, None
|
507 |
+
|
508 |
+
def get_answer_at_once(self):
|
509 |
+
question = self.history[-1]["content"]
|
510 |
+
conv_id = str(uuid.uuid4())
|
511 |
+
self.last_conv_id = conv_id
|
512 |
+
data = {
|
513 |
+
"user_id": self.api_key,
|
514 |
+
"session_id": self.session_id,
|
515 |
+
"uuid": conv_id,
|
516 |
+
"data_type": "text",
|
517 |
+
"data": question
|
518 |
+
}
|
519 |
+
response = requests.post(self.url, json=data)
|
520 |
+
try:
|
521 |
+
response = json.loads(response.text)
|
522 |
+
return response["data"], len(response["data"])
|
523 |
+
except Exception as e:
|
524 |
+
return response.text, len(response.text)
|
525 |
+
|
526 |
+
|
527 |
+
|
528 |
+
|
529 |
+
def get_model(
|
530 |
+
model_name,
|
531 |
+
lora_model_path=None,
|
532 |
+
access_key=None,
|
533 |
+
temperature=None,
|
534 |
+
top_p=None,
|
535 |
+
system_prompt=None,
|
536 |
+
) -> BaseLLMModel:
|
537 |
+
msg = i18n("模型设置为了:") + f" {model_name}"
|
538 |
+
model_type = ModelType.get_type(model_name)
|
539 |
+
lora_selector_visibility = False
|
540 |
+
lora_choices = []
|
541 |
+
dont_change_lora_selector = False
|
542 |
+
if model_type != ModelType.OpenAI:
|
543 |
+
config.local_embedding = True
|
544 |
+
# del current_model.model
|
545 |
+
model = None
|
546 |
+
try:
|
547 |
+
if model_type == ModelType.OpenAI:
|
548 |
+
logging.info(f"正在加载OpenAI模型: {model_name}")
|
549 |
+
model = OpenAIClient(
|
550 |
+
model_name=model_name,
|
551 |
+
api_key=access_key,
|
552 |
+
system_prompt=system_prompt,
|
553 |
+
temperature=temperature,
|
554 |
+
top_p=top_p,
|
555 |
+
)
|
556 |
+
elif model_type == ModelType.ChatGLM:
|
557 |
+
logging.info(f"正在加载ChatGLM模型: {model_name}")
|
558 |
+
model = ChatGLM_Client(model_name)
|
559 |
+
elif model_type == ModelType.LLaMA and lora_model_path == "":
|
560 |
+
msg = f"现在请为 {model_name} 选择LoRA模型"
|
561 |
+
logging.info(msg)
|
562 |
+
lora_selector_visibility = True
|
563 |
+
if os.path.isdir("lora"):
|
564 |
+
lora_choices = get_file_names(
|
565 |
+
"lora", plain=True, filetypes=[""])
|
566 |
+
lora_choices = ["No LoRA"] + lora_choices
|
567 |
+
elif model_type == ModelType.LLaMA and lora_model_path != "":
|
568 |
+
logging.info(f"正在加载LLaMA模型: {model_name} + {lora_model_path}")
|
569 |
+
dont_change_lora_selector = True
|
570 |
+
if lora_model_path == "No LoRA":
|
571 |
+
lora_model_path = None
|
572 |
+
msg += " + No LoRA"
|
573 |
+
else:
|
574 |
+
msg += f" + {lora_model_path}"
|
575 |
+
model = LLaMA_Client(model_name, lora_model_path)
|
576 |
+
elif model_type == ModelType.XMChat:
|
577 |
+
if os.environ.get("XMCHAT_API_KEY") != "":
|
578 |
+
access_key = os.environ.get("XMCHAT_API_KEY")
|
579 |
+
model = XMChat(api_key=access_key)
|
580 |
+
elif model_type == ModelType.Unknown:
|
581 |
+
raise ValueError(f"未知模型: {model_name}")
|
582 |
+
logging.info(msg)
|
583 |
+
except Exception as e:
|
584 |
+
logging.error(e)
|
585 |
+
msg = f"{STANDARD_ERROR_MSG}: {e}"
|
586 |
+
if dont_change_lora_selector:
|
587 |
+
return model, msg
|
588 |
+
else:
|
589 |
+
return model, msg, gr.Dropdown.update(choices=lora_choices, visible=lora_selector_visibility)
|
590 |
+
|
591 |
+
|
592 |
+
if __name__ == "__main__":
|
593 |
+
with open("config.json", "r") as f:
|
594 |
+
openai_api_key = cjson.load(f)["openai_api_key"]
|
595 |
+
# set logging level to debug
|
596 |
+
logging.basicConfig(level=logging.DEBUG)
|
597 |
+
# client = ModelManager(model_name="gpt-3.5-turbo", access_key=openai_api_key)
|
598 |
+
client = get_model(model_name="chatglm-6b-int4")
|
599 |
+
chatbot = []
|
600 |
+
stream = False
|
601 |
+
# 测试账单功能
|
602 |
+
logging.info(colorama.Back.GREEN + "测试账单功能" + colorama.Back.RESET)
|
603 |
+
logging.info(client.billing_info())
|
604 |
+
# 测试问答
|
605 |
+
logging.info(colorama.Back.GREEN + "测试问答" + colorama.Back.RESET)
|
606 |
+
question = "巴黎是中国的首都吗?"
|
607 |
+
for i in client.predict(inputs=question, chatbot=chatbot, stream=stream):
|
608 |
+
logging.info(i)
|
609 |
+
logging.info(f"测试问答后history : {client.history}")
|
610 |
+
# 测试记忆力
|
611 |
+
logging.info(colorama.Back.GREEN + "测试记忆力" + colorama.Back.RESET)
|
612 |
+
question = "我刚刚问了你什么问题?"
|
613 |
+
for i in client.predict(inputs=question, chatbot=chatbot, stream=stream):
|
614 |
+
logging.info(i)
|
615 |
+
logging.info(f"测试记忆力后history : {client.history}")
|
616 |
+
# 测试重试功能
|
617 |
+
logging.info(colorama.Back.GREEN + "测试重试功能" + colorama.Back.RESET)
|
618 |
+
for i in client.retry(chatbot=chatbot, stream=stream):
|
619 |
+
logging.info(i)
|
620 |
+
logging.info(f"重试后history : {client.history}")
|
621 |
+
# # 测试总结功能
|
622 |
+
# print(colorama.Back.GREEN + "测试总结功能" + colorama.Back.RESET)
|
623 |
+
# chatbot, msg = client.reduce_token_size(chatbot=chatbot)
|
624 |
+
# print(chatbot, msg)
|
625 |
+
# print(f"总结后history: {client.history}")
|
modules/models/Google_PaLM.py
DELETED
@@ -1,26 +0,0 @@
|
|
1 |
-
from .base_model import BaseLLMModel
|
2 |
-
import google.generativeai as palm
|
3 |
-
|
4 |
-
class Google_PaLM_Client(BaseLLMModel):
|
5 |
-
def __init__(self, model_name, api_key, user_name="") -> None:
|
6 |
-
super().__init__(model_name=model_name, user=user_name)
|
7 |
-
self.api_key = api_key
|
8 |
-
|
9 |
-
def _get_palm_style_input(self):
|
10 |
-
new_history = []
|
11 |
-
for item in self.history:
|
12 |
-
if item["role"] == "user":
|
13 |
-
new_history.append({'author': '1', 'content': item["content"]})
|
14 |
-
else:
|
15 |
-
new_history.append({'author': '0', 'content': item["content"]})
|
16 |
-
return new_history
|
17 |
-
|
18 |
-
def get_answer_at_once(self):
|
19 |
-
palm.configure(api_key=self.api_key)
|
20 |
-
messages = self._get_palm_style_input()
|
21 |
-
response = palm.chat(context=self.system_prompt, messages=messages, temperature=self.temperature, top_p=self.top_p)
|
22 |
-
if response.last is not None:
|
23 |
-
return response.last, len(response.last)
|
24 |
-
else:
|
25 |
-
reasons = '\n\n'.join(reason['reason'].name for reason in response.filters)
|
26 |
-
return "由于下面的原因,Google 拒绝返回 PaLM 的回答:\n\n" + reasons, 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
modules/models/azure.py
DELETED
@@ -1,17 +0,0 @@
|
|
1 |
-
from langchain.chat_models import AzureChatOpenAI
|
2 |
-
import os
|
3 |
-
|
4 |
-
from .base_model import Base_Chat_Langchain_Client
|
5 |
-
|
6 |
-
# load_config_to_environ(["azure_openai_api_key", "azure_api_base_url", "azure_openai_api_version", "azure_deployment_name"])
|
7 |
-
|
8 |
-
class Azure_OpenAI_Client(Base_Chat_Langchain_Client):
|
9 |
-
def setup_model(self):
|
10 |
-
# inplement this to setup the model then return it
|
11 |
-
return AzureChatOpenAI(
|
12 |
-
openai_api_base=os.environ["AZURE_OPENAI_API_BASE_URL"],
|
13 |
-
openai_api_version=os.environ["AZURE_OPENAI_API_VERSION"],
|
14 |
-
deployment_name=os.environ["AZURE_DEPLOYMENT_NAME"],
|
15 |
-
openai_api_key=os.environ["AZURE_OPENAI_API_KEY"],
|
16 |
-
openai_api_type="azure",
|
17 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
modules/models/base_model.py
CHANGED
@@ -29,8 +29,6 @@ from langchain.input import print_text
|
|
29 |
from langchain.schema import AgentAction, AgentFinish, LLMResult
|
30 |
from threading import Thread, Condition
|
31 |
from collections import deque
|
32 |
-
from langchain.chat_models.base import BaseChatModel
|
33 |
-
from langchain.schema import HumanMessage, AIMessage, SystemMessage, BaseMessage
|
34 |
|
35 |
from ..presets import *
|
36 |
from ..index_func import *
|
@@ -38,7 +36,6 @@ from ..utils import *
|
|
38 |
from .. import shared
|
39 |
from ..config import retrieve_proxy
|
40 |
|
41 |
-
|
42 |
class CallbackToIterator:
|
43 |
def __init__(self):
|
44 |
self.queue = deque()
|
@@ -55,8 +52,7 @@ class CallbackToIterator:
|
|
55 |
|
56 |
def __next__(self):
|
57 |
with self.cond:
|
58 |
-
# Wait for a value to be added to the queue.
|
59 |
-
while not self.queue and not self.finished:
|
60 |
self.cond.wait()
|
61 |
if not self.queue:
|
62 |
raise StopIteration()
|
@@ -67,7 +63,6 @@ class CallbackToIterator:
|
|
67 |
self.finished = True
|
68 |
self.cond.notify() # Wake up the generator if it's waiting.
|
69 |
|
70 |
-
|
71 |
def get_action_description(text):
|
72 |
match = re.search('```(.*?)```', text, re.S)
|
73 |
json_text = match.group(1)
|
@@ -81,7 +76,6 @@ def get_action_description(text):
|
|
81 |
else:
|
82 |
return ""
|
83 |
|
84 |
-
|
85 |
class ChuanhuCallbackHandler(BaseCallbackHandler):
|
86 |
|
87 |
def __init__(self, callback) -> None:
|
@@ -123,10 +117,6 @@ class ChuanhuCallbackHandler(BaseCallbackHandler):
|
|
123 |
"""Run on new LLM token. Only available when streaming is enabled."""
|
124 |
self.callback(token)
|
125 |
|
126 |
-
def on_chat_model_start(self, serialized: Dict[str, Any], messages: List[List[BaseMessage]], **kwargs: Any) -> Any:
|
127 |
-
"""Run when a chat model starts running."""
|
128 |
-
pass
|
129 |
-
|
130 |
|
131 |
class ModelType(Enum):
|
132 |
Unknown = -1
|
@@ -139,8 +129,6 @@ class ModelType(Enum):
|
|
139 |
YuanAI = 6
|
140 |
Minimax = 7
|
141 |
ChuanhuAgent = 8
|
142 |
-
GooglePaLM = 9
|
143 |
-
LangchainChat = 10
|
144 |
|
145 |
@classmethod
|
146 |
def get_type(cls, model_name: str):
|
@@ -164,10 +152,6 @@ class ModelType(Enum):
|
|
164 |
model_type = ModelType.Minimax
|
165 |
elif "川虎助理" in model_name_lower:
|
166 |
model_type = ModelType.ChuanhuAgent
|
167 |
-
elif "palm" in model_name_lower:
|
168 |
-
model_type = ModelType.GooglePaLM
|
169 |
-
elif "azure" or "api" in model_name_lower:
|
170 |
-
model_type = ModelType.LangchainChat
|
171 |
else:
|
172 |
model_type = ModelType.Unknown
|
173 |
return model_type
|
@@ -177,7 +161,7 @@ class BaseLLMModel:
|
|
177 |
def __init__(
|
178 |
self,
|
179 |
model_name,
|
180 |
-
system_prompt=
|
181 |
temperature=1.0,
|
182 |
top_p=1.0,
|
183 |
n_choices=1,
|
@@ -217,8 +201,7 @@ class BaseLLMModel:
|
|
217 |
conversations are stored in self.history, with the most recent question, in OpenAI format
|
218 |
should return a generator, each time give the next word (str) in the answer
|
219 |
"""
|
220 |
-
logging.warning(
|
221 |
-
"stream predict not implemented, using at once predict instead")
|
222 |
response, _ = self.get_answer_at_once()
|
223 |
yield response
|
224 |
|
@@ -229,8 +212,7 @@ class BaseLLMModel:
|
|
229 |
the answer (str)
|
230 |
total token count (int)
|
231 |
"""
|
232 |
-
logging.warning(
|
233 |
-
"at once predict not implemented, using stream predict instead")
|
234 |
response_iter = self.get_answer_stream_iter()
|
235 |
count = 0
|
236 |
for response in response_iter:
|
@@ -264,7 +246,7 @@ class BaseLLMModel:
|
|
264 |
stream_iter = self.get_answer_stream_iter()
|
265 |
|
266 |
if display_append:
|
267 |
-
display_append =
|
268 |
for partial_text in stream_iter:
|
269 |
chatbot[-1] = (chatbot[-1][0], partial_text + display_append)
|
270 |
self.all_token_counts[-1] += 1
|
@@ -291,11 +273,9 @@ class BaseLLMModel:
|
|
291 |
self.history[-2] = construct_user(fake_input)
|
292 |
chatbot[-1] = (chatbot[-1][0], ai_reply + display_append)
|
293 |
if fake_input is not None:
|
294 |
-
self.all_token_counts[-1] += count_token(
|
295 |
-
construct_assistant(ai_reply))
|
296 |
else:
|
297 |
-
self.all_token_counts[-1] = total_token_count -
|
298 |
-
sum(self.all_token_counts)
|
299 |
status_text = self.token_message()
|
300 |
return chatbot, status_text
|
301 |
|
@@ -319,13 +299,10 @@ class BaseLLMModel:
|
|
319 |
from langchain.chat_models import ChatOpenAI
|
320 |
from langchain.callbacks import StdOutCallbackHandler
|
321 |
prompt_template = "Write a concise summary of the following:\n\n{text}\n\nCONCISE SUMMARY IN " + language + ":"
|
322 |
-
PROMPT = PromptTemplate(
|
323 |
-
template=prompt_template, input_variables=["text"])
|
324 |
llm = ChatOpenAI()
|
325 |
-
chain = load_summarize_chain(
|
326 |
-
|
327 |
-
summary = chain({"input_documents": list(index.docstore.__dict__[
|
328 |
-
"_dict"].values())}, return_only_outputs=True)["output_text"]
|
329 |
print(i18n("总结") + f": {summary}")
|
330 |
chatbot.append([i18n("上传了")+str(len(files))+"个文件", summary])
|
331 |
return chatbot, status
|
@@ -346,12 +323,9 @@ class BaseLLMModel:
|
|
346 |
msg = "索引获取成功,生成回答中……"
|
347 |
logging.info(msg)
|
348 |
with retrieve_proxy():
|
349 |
-
retriever = VectorStoreRetriever(vectorstore=index, search_type="similarity_score_threshold",
|
350 |
-
|
351 |
-
|
352 |
-
real_inputs)
|
353 |
-
reference_results = [[d.page_content.strip("�"), os.path.basename(
|
354 |
-
d.metadata["source"])] for d in relevant_documents]
|
355 |
reference_results = add_source_numbers(reference_results)
|
356 |
display_append = add_details(reference_results)
|
357 |
display_append = "\n\n" + "".join(display_append)
|
@@ -374,12 +348,10 @@ class BaseLLMModel:
|
|
374 |
reference_results.append([result['body'], result['href']])
|
375 |
display_append.append(
|
376 |
# f"{idx+1}. [{domain_name}]({result['href']})\n"
|
377 |
-
f"<a href=\"{result['href']}\" target=\"_blank\">{
|
378 |
)
|
379 |
reference_results = add_source_numbers(reference_results)
|
380 |
-
|
381 |
-
display_append = '<div class = "source-a">' + \
|
382 |
-
"".join(display_append) + '</div>'
|
383 |
real_inputs = (
|
384 |
replace_today(WEBSEARCH_PTOMPT_TEMPLATE)
|
385 |
.replace("{query}", real_inputs)
|
@@ -403,16 +375,14 @@ class BaseLLMModel:
|
|
403 |
|
404 |
status_text = "开始生成回答……"
|
405 |
logging.info(
|
406 |
-
|
407 |
-
colorama.Fore.BLUE + f"{inputs}" + colorama.Style.RESET_ALL
|
408 |
)
|
409 |
if should_check_token_count:
|
410 |
yield chatbot + [(inputs, "")], status_text
|
411 |
if reply_language == "跟随问题语言(不稳定)":
|
412 |
reply_language = "the same language as the question, such as English, 中文, 日本語, Español, Français, or Deutsch."
|
413 |
|
414 |
-
limited_context, fake_inputs, display_append, inputs, chatbot = self.prepare_inputs(
|
415 |
-
real_inputs=inputs, use_websearch=use_websearch, files=files, reply_language=reply_language, chatbot=chatbot)
|
416 |
yield chatbot + [(fake_inputs, "")], status_text
|
417 |
|
418 |
if (
|
@@ -598,13 +568,10 @@ class BaseLLMModel:
|
|
598 |
self.system_prompt = new_system_prompt
|
599 |
|
600 |
def set_key(self, new_access_key):
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
return self.api_key, msg
|
606 |
-
else:
|
607 |
-
return gr.update(), gr.update()
|
608 |
|
609 |
def set_single_turn(self, new_single_turn):
|
610 |
self.single_turn = new_single_turn
|
@@ -613,8 +580,7 @@ class BaseLLMModel:
|
|
613 |
self.history = []
|
614 |
self.all_token_counts = []
|
615 |
self.interrupted = False
|
616 |
-
pathlib.Path(os.path.join(HISTORY_DIR, self.user_identifier, new_auto_history_filename(
|
617 |
-
os.path.join(HISTORY_DIR, self.user_identifier)))).touch()
|
618 |
return [], self.token_message([0])
|
619 |
|
620 |
def delete_first_conversation(self):
|
@@ -657,8 +623,7 @@ class BaseLLMModel:
|
|
657 |
|
658 |
def auto_save(self, chatbot):
|
659 |
history_file_path = get_history_filepath(self.user_identifier)
|
660 |
-
save_file(history_file_path, self.system_prompt,
|
661 |
-
self.history, chatbot, self.user_identifier)
|
662 |
|
663 |
def export_markdown(self, filename, chatbot, user_name):
|
664 |
if filename == "":
|
@@ -674,8 +639,7 @@ class BaseLLMModel:
|
|
674 |
filename = filename.name
|
675 |
try:
|
676 |
if "/" not in filename:
|
677 |
-
history_file_path = os.path.join(
|
678 |
-
HISTORY_DIR, user_name, filename)
|
679 |
else:
|
680 |
history_file_path = filename
|
681 |
with open(history_file_path, "r", encoding="utf-8") as f:
|
@@ -701,33 +665,15 @@ class BaseLLMModel:
|
|
701 |
logging.info(f"没有找到对话历史记录 {filename}")
|
702 |
return gr.update(), self.system_prompt, gr.update()
|
703 |
|
704 |
-
def delete_chat_history(self, filename, user_name):
|
705 |
-
if filename == "CANCELED":
|
706 |
-
return gr.update(), gr.update(), gr.update()
|
707 |
-
if filename == "":
|
708 |
-
return i18n("你没有选择任何对话历史"), gr.update(), gr.update()
|
709 |
-
if not filename.endswith(".json"):
|
710 |
-
filename += ".json"
|
711 |
-
if "/" not in filename:
|
712 |
-
history_file_path = os.path.join(HISTORY_DIR, user_name, filename)
|
713 |
-
else:
|
714 |
-
history_file_path = filename
|
715 |
-
try:
|
716 |
-
os.remove(history_file_path)
|
717 |
-
return i18n("删除对话历史成功"), get_history_names(False, user_name), []
|
718 |
-
except:
|
719 |
-
logging.info(f"删除对话历史失败 {history_file_path}")
|
720 |
-
return i18n("对话历史")+filename+i18n("已经被删除啦"), gr.update(), gr.update()
|
721 |
-
|
722 |
def auto_load(self):
|
723 |
if self.user_identifier == "":
|
724 |
self.reset()
|
725 |
return self.system_prompt, gr.update()
|
726 |
history_file_path = get_history_filepath(self.user_identifier)
|
727 |
-
filename, system_prompt, chatbot = self.load_chat_history(
|
728 |
-
history_file_path, self.user_identifier)
|
729 |
return system_prompt, chatbot
|
730 |
|
|
|
731 |
def like(self):
|
732 |
"""like the last response, implement if needed
|
733 |
"""
|
@@ -737,47 +683,3 @@ class BaseLLMModel:
|
|
737 |
"""dislike the last response, implement if needed
|
738 |
"""
|
739 |
return gr.update()
|
740 |
-
|
741 |
-
|
742 |
-
class Base_Chat_Langchain_Client(BaseLLMModel):
|
743 |
-
def __init__(self, model_name, user_name=""):
|
744 |
-
super().__init__(model_name, user=user_name)
|
745 |
-
self.need_api_key = False
|
746 |
-
self.model = self.setup_model()
|
747 |
-
|
748 |
-
def setup_model(self):
|
749 |
-
# inplement this to setup the model then return it
|
750 |
-
pass
|
751 |
-
|
752 |
-
def _get_langchain_style_history(self):
|
753 |
-
history = [SystemMessage(content=self.system_prompt)]
|
754 |
-
for i in self.history:
|
755 |
-
if i["role"] == "user":
|
756 |
-
history.append(HumanMessage(content=i["content"]))
|
757 |
-
elif i["role"] == "assistant":
|
758 |
-
history.append(AIMessage(content=i["content"]))
|
759 |
-
return history
|
760 |
-
|
761 |
-
def get_answer_at_once(self):
|
762 |
-
assert isinstance(
|
763 |
-
self.model, BaseChatModel), "model is not instance of LangChain BaseChatModel"
|
764 |
-
history = self._get_langchain_style_history()
|
765 |
-
response = self.model.generate(history)
|
766 |
-
return response.content, sum(response.content)
|
767 |
-
|
768 |
-
def get_answer_stream_iter(self):
|
769 |
-
it = CallbackToIterator()
|
770 |
-
assert isinstance(
|
771 |
-
self.model, BaseChatModel), "model is not instance of LangChain BaseChatModel"
|
772 |
-
history = self._get_langchain_style_history()
|
773 |
-
|
774 |
-
def thread_func():
|
775 |
-
self.model(messages=history, callbacks=[
|
776 |
-
ChuanhuCallbackHandler(it.callback)])
|
777 |
-
it.finish()
|
778 |
-
t = Thread(target=thread_func)
|
779 |
-
t.start()
|
780 |
-
partial_text = ""
|
781 |
-
for value in it:
|
782 |
-
partial_text += value
|
783 |
-
yield partial_text
|
|
|
29 |
from langchain.schema import AgentAction, AgentFinish, LLMResult
|
30 |
from threading import Thread, Condition
|
31 |
from collections import deque
|
|
|
|
|
32 |
|
33 |
from ..presets import *
|
34 |
from ..index_func import *
|
|
|
36 |
from .. import shared
|
37 |
from ..config import retrieve_proxy
|
38 |
|
|
|
39 |
class CallbackToIterator:
|
40 |
def __init__(self):
|
41 |
self.queue = deque()
|
|
|
52 |
|
53 |
def __next__(self):
|
54 |
with self.cond:
|
55 |
+
while not self.queue and not self.finished: # Wait for a value to be added to the queue.
|
|
|
56 |
self.cond.wait()
|
57 |
if not self.queue:
|
58 |
raise StopIteration()
|
|
|
63 |
self.finished = True
|
64 |
self.cond.notify() # Wake up the generator if it's waiting.
|
65 |
|
|
|
66 |
def get_action_description(text):
|
67 |
match = re.search('```(.*?)```', text, re.S)
|
68 |
json_text = match.group(1)
|
|
|
76 |
else:
|
77 |
return ""
|
78 |
|
|
|
79 |
class ChuanhuCallbackHandler(BaseCallbackHandler):
|
80 |
|
81 |
def __init__(self, callback) -> None:
|
|
|
117 |
"""Run on new LLM token. Only available when streaming is enabled."""
|
118 |
self.callback(token)
|
119 |
|
|
|
|
|
|
|
|
|
120 |
|
121 |
class ModelType(Enum):
|
122 |
Unknown = -1
|
|
|
129 |
YuanAI = 6
|
130 |
Minimax = 7
|
131 |
ChuanhuAgent = 8
|
|
|
|
|
132 |
|
133 |
@classmethod
|
134 |
def get_type(cls, model_name: str):
|
|
|
152 |
model_type = ModelType.Minimax
|
153 |
elif "川虎助理" in model_name_lower:
|
154 |
model_type = ModelType.ChuanhuAgent
|
|
|
|
|
|
|
|
|
155 |
else:
|
156 |
model_type = ModelType.Unknown
|
157 |
return model_type
|
|
|
161 |
def __init__(
|
162 |
self,
|
163 |
model_name,
|
164 |
+
system_prompt="",
|
165 |
temperature=1.0,
|
166 |
top_p=1.0,
|
167 |
n_choices=1,
|
|
|
201 |
conversations are stored in self.history, with the most recent question, in OpenAI format
|
202 |
should return a generator, each time give the next word (str) in the answer
|
203 |
"""
|
204 |
+
logging.warning("stream predict not implemented, using at once predict instead")
|
|
|
205 |
response, _ = self.get_answer_at_once()
|
206 |
yield response
|
207 |
|
|
|
212 |
the answer (str)
|
213 |
total token count (int)
|
214 |
"""
|
215 |
+
logging.warning("at once predict not implemented, using stream predict instead")
|
|
|
216 |
response_iter = self.get_answer_stream_iter()
|
217 |
count = 0
|
218 |
for response in response_iter:
|
|
|
246 |
stream_iter = self.get_answer_stream_iter()
|
247 |
|
248 |
if display_append:
|
249 |
+
display_append = "<hr>" +display_append
|
250 |
for partial_text in stream_iter:
|
251 |
chatbot[-1] = (chatbot[-1][0], partial_text + display_append)
|
252 |
self.all_token_counts[-1] += 1
|
|
|
273 |
self.history[-2] = construct_user(fake_input)
|
274 |
chatbot[-1] = (chatbot[-1][0], ai_reply + display_append)
|
275 |
if fake_input is not None:
|
276 |
+
self.all_token_counts[-1] += count_token(construct_assistant(ai_reply))
|
|
|
277 |
else:
|
278 |
+
self.all_token_counts[-1] = total_token_count - sum(self.all_token_counts)
|
|
|
279 |
status_text = self.token_message()
|
280 |
return chatbot, status_text
|
281 |
|
|
|
299 |
from langchain.chat_models import ChatOpenAI
|
300 |
from langchain.callbacks import StdOutCallbackHandler
|
301 |
prompt_template = "Write a concise summary of the following:\n\n{text}\n\nCONCISE SUMMARY IN " + language + ":"
|
302 |
+
PROMPT = PromptTemplate(template=prompt_template, input_variables=["text"])
|
|
|
303 |
llm = ChatOpenAI()
|
304 |
+
chain = load_summarize_chain(llm, chain_type="map_reduce", return_intermediate_steps=True, map_prompt=PROMPT, combine_prompt=PROMPT)
|
305 |
+
summary = chain({"input_documents": list(index.docstore.__dict__["_dict"].values())}, return_only_outputs=True)["output_text"]
|
|
|
|
|
306 |
print(i18n("总结") + f": {summary}")
|
307 |
chatbot.append([i18n("上传了")+str(len(files))+"个文件", summary])
|
308 |
return chatbot, status
|
|
|
323 |
msg = "索引获取成功,生成回答中……"
|
324 |
logging.info(msg)
|
325 |
with retrieve_proxy():
|
326 |
+
retriever = VectorStoreRetriever(vectorstore=index, search_type="similarity_score_threshold",search_kwargs={"k":6, "score_threshold": 0.5})
|
327 |
+
relevant_documents = retriever.get_relevant_documents(real_inputs)
|
328 |
+
reference_results = [[d.page_content.strip("�"), os.path.basename(d.metadata["source"])] for d in relevant_documents]
|
|
|
|
|
|
|
329 |
reference_results = add_source_numbers(reference_results)
|
330 |
display_append = add_details(reference_results)
|
331 |
display_append = "\n\n" + "".join(display_append)
|
|
|
348 |
reference_results.append([result['body'], result['href']])
|
349 |
display_append.append(
|
350 |
# f"{idx+1}. [{domain_name}]({result['href']})\n"
|
351 |
+
f"<li><a href=\"{result['href']}\" target=\"_blank\">{result['title']}</a></li>\n"
|
352 |
)
|
353 |
reference_results = add_source_numbers(reference_results)
|
354 |
+
display_append = "<ol>\n\n" + "".join(display_append) + "</ol>"
|
|
|
|
|
355 |
real_inputs = (
|
356 |
replace_today(WEBSEARCH_PTOMPT_TEMPLATE)
|
357 |
.replace("{query}", real_inputs)
|
|
|
375 |
|
376 |
status_text = "开始生成回答……"
|
377 |
logging.info(
|
378 |
+
"用户" + f"{self.user_identifier}" + "的输入为:" + colorama.Fore.BLUE + f"{inputs}" + colorama.Style.RESET_ALL
|
|
|
379 |
)
|
380 |
if should_check_token_count:
|
381 |
yield chatbot + [(inputs, "")], status_text
|
382 |
if reply_language == "跟随问题语言(不稳定)":
|
383 |
reply_language = "the same language as the question, such as English, 中文, 日本語, Español, Français, or Deutsch."
|
384 |
|
385 |
+
limited_context, fake_inputs, display_append, inputs, chatbot = self.prepare_inputs(real_inputs=inputs, use_websearch=use_websearch, files=files, reply_language=reply_language, chatbot=chatbot)
|
|
|
386 |
yield chatbot + [(fake_inputs, "")], status_text
|
387 |
|
388 |
if (
|
|
|
568 |
self.system_prompt = new_system_prompt
|
569 |
|
570 |
def set_key(self, new_access_key):
|
571 |
+
self.api_key = new_access_key.strip()
|
572 |
+
msg = i18n("API密钥更改为了") + hide_middle_chars(self.api_key)
|
573 |
+
logging.info(msg)
|
574 |
+
return self.api_key, msg
|
|
|
|
|
|
|
575 |
|
576 |
def set_single_turn(self, new_single_turn):
|
577 |
self.single_turn = new_single_turn
|
|
|
580 |
self.history = []
|
581 |
self.all_token_counts = []
|
582 |
self.interrupted = False
|
583 |
+
pathlib.Path(os.path.join(HISTORY_DIR, self.user_identifier, new_auto_history_filename(os.path.join(HISTORY_DIR, self.user_identifier)))).touch()
|
|
|
584 |
return [], self.token_message([0])
|
585 |
|
586 |
def delete_first_conversation(self):
|
|
|
623 |
|
624 |
def auto_save(self, chatbot):
|
625 |
history_file_path = get_history_filepath(self.user_identifier)
|
626 |
+
save_file(history_file_path, self.system_prompt, self.history, chatbot, self.user_identifier)
|
|
|
627 |
|
628 |
def export_markdown(self, filename, chatbot, user_name):
|
629 |
if filename == "":
|
|
|
639 |
filename = filename.name
|
640 |
try:
|
641 |
if "/" not in filename:
|
642 |
+
history_file_path = os.path.join(HISTORY_DIR, user_name, filename)
|
|
|
643 |
else:
|
644 |
history_file_path = filename
|
645 |
with open(history_file_path, "r", encoding="utf-8") as f:
|
|
|
665 |
logging.info(f"没有找到对话历史记录 {filename}")
|
666 |
return gr.update(), self.system_prompt, gr.update()
|
667 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
668 |
def auto_load(self):
|
669 |
if self.user_identifier == "":
|
670 |
self.reset()
|
671 |
return self.system_prompt, gr.update()
|
672 |
history_file_path = get_history_filepath(self.user_identifier)
|
673 |
+
filename, system_prompt, chatbot = self.load_chat_history(history_file_path, self.user_identifier)
|
|
|
674 |
return system_prompt, chatbot
|
675 |
|
676 |
+
|
677 |
def like(self):
|
678 |
"""like the last response, implement if needed
|
679 |
"""
|
|
|
683 |
"""dislike the last response, implement if needed
|
684 |
"""
|
685 |
return gr.update()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
modules/models/models.py
CHANGED
@@ -24,7 +24,7 @@ from ..presets import *
|
|
24 |
from ..index_func import *
|
25 |
from ..utils import *
|
26 |
from .. import shared
|
27 |
-
from ..config import retrieve_proxy, usage_limit
|
28 |
from modules import config
|
29 |
from .base_model import BaseLLMModel, ModelType
|
30 |
|
@@ -87,22 +87,21 @@ class OpenAIClient(BaseLLMModel):
|
|
87 |
try:
|
88 |
usage_data = self._get_billing_data(usage_url)
|
89 |
except Exception as e:
|
90 |
-
|
91 |
-
if "Invalid authorization header" in str(e):
|
92 |
-
return i18n("**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id")
|
93 |
-
elif "Incorrect API key provided: sess" in str(e):
|
94 |
-
return i18n("**获取API使用情况失败**,sensitive_id错误或已过期")
|
95 |
return i18n("**获取API使用情况失败**")
|
96 |
# rounded_usage = "{:.5f}".format(usage_data["total_usage"] / 100)
|
97 |
rounded_usage = round(usage_data["total_usage"] / 100, 5)
|
98 |
usage_percent = round(usage_data["total_usage"] / usage_limit, 2)
|
99 |
# return i18n("**本月使用金额** ") + f"\u3000 ${rounded_usage}"
|
100 |
-
return
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
|
|
|
|
|
|
106 |
except requests.exceptions.ConnectTimeout:
|
107 |
status_text = (
|
108 |
STANDARD_ERROR_MSG + CONNECTION_TIMEOUT_MSG + ERROR_RETRIEVE_MSG
|
@@ -180,10 +179,9 @@ class OpenAIClient(BaseLLMModel):
|
|
180 |
def _refresh_header(self):
|
181 |
self.headers = {
|
182 |
"Content-Type": "application/json",
|
183 |
-
"Authorization": f"Bearer {
|
184 |
}
|
185 |
|
186 |
-
|
187 |
def _get_billing_data(self, billing_url):
|
188 |
with retrieve_proxy():
|
189 |
response = requests.get(
|
@@ -562,7 +560,6 @@ def get_model(
|
|
562 |
try:
|
563 |
if model_type == ModelType.OpenAI:
|
564 |
logging.info(f"正在加载OpenAI模型: {model_name}")
|
565 |
-
access_key = os.environ.get("OPENAI_API_KEY", access_key)
|
566 |
model = OpenAIClient(
|
567 |
model_name=model_name,
|
568 |
api_key=access_key,
|
@@ -613,25 +610,16 @@ def get_model(
|
|
613 |
elif model_type == ModelType.ChuanhuAgent:
|
614 |
from .ChuanhuAgent import ChuanhuAgent_Client
|
615 |
model = ChuanhuAgent_Client(model_name, access_key, user_name=user_name)
|
616 |
-
elif model_type == ModelType.GooglePaLM:
|
617 |
-
from .Google_PaLM import Google_PaLM_Client
|
618 |
-
access_key = os.environ.get("GOOGLE_PALM_API_KEY", access_key)
|
619 |
-
model = Google_PaLM_Client(model_name, access_key, user_name=user_name)
|
620 |
-
elif model_type == ModelType.LangchainChat:
|
621 |
-
from .azure import Azure_OpenAI_Client
|
622 |
-
model = Azure_OpenAI_Client(model_name, user_name=user_name)
|
623 |
elif model_type == ModelType.Unknown:
|
624 |
raise ValueError(f"未知模型: {model_name}")
|
625 |
logging.info(msg)
|
626 |
except Exception as e:
|
627 |
-
|
628 |
-
traceback.print_exc()
|
629 |
msg = f"{STANDARD_ERROR_MSG}: {e}"
|
630 |
-
presudo_key = hide_middle_chars(access_key)
|
631 |
if dont_change_lora_selector:
|
632 |
-
return model, msg, chatbot
|
633 |
else:
|
634 |
-
return model, msg, chatbot, gr.Dropdown.update(choices=lora_choices, visible=lora_selector_visibility)
|
635 |
|
636 |
|
637 |
if __name__ == "__main__":
|
|
|
24 |
from ..index_func import *
|
25 |
from ..utils import *
|
26 |
from .. import shared
|
27 |
+
from ..config import retrieve_proxy, usage_limit
|
28 |
from modules import config
|
29 |
from .base_model import BaseLLMModel, ModelType
|
30 |
|
|
|
87 |
try:
|
88 |
usage_data = self._get_billing_data(usage_url)
|
89 |
except Exception as e:
|
90 |
+
logging.error(f"获取API使用情况失败:" + str(e))
|
|
|
|
|
|
|
|
|
91 |
return i18n("**获取API使用情况失败**")
|
92 |
# rounded_usage = "{:.5f}".format(usage_data["total_usage"] / 100)
|
93 |
rounded_usage = round(usage_data["total_usage"] / 100, 5)
|
94 |
usage_percent = round(usage_data["total_usage"] / usage_limit, 2)
|
95 |
# return i18n("**本月使用金额** ") + f"\u3000 ${rounded_usage}"
|
96 |
+
return """\
|
97 |
+
<b>""" + i18n("本月使用金额") + f"""</b>
|
98 |
+
<div class="progress-bar">
|
99 |
+
<div class="progress" style="width: {usage_percent}%;">
|
100 |
+
<span class="progress-text">{usage_percent}%</span>
|
101 |
+
</div>
|
102 |
+
</div>
|
103 |
+
<div style="display: flex; justify-content: space-between;"><span>${rounded_usage}</span><span>${usage_limit}</span></div>
|
104 |
+
"""
|
105 |
except requests.exceptions.ConnectTimeout:
|
106 |
status_text = (
|
107 |
STANDARD_ERROR_MSG + CONNECTION_TIMEOUT_MSG + ERROR_RETRIEVE_MSG
|
|
|
179 |
def _refresh_header(self):
|
180 |
self.headers = {
|
181 |
"Content-Type": "application/json",
|
182 |
+
"Authorization": f"Bearer {self.api_key}",
|
183 |
}
|
184 |
|
|
|
185 |
def _get_billing_data(self, billing_url):
|
186 |
with retrieve_proxy():
|
187 |
response = requests.get(
|
|
|
560 |
try:
|
561 |
if model_type == ModelType.OpenAI:
|
562 |
logging.info(f"正在加载OpenAI模型: {model_name}")
|
|
|
563 |
model = OpenAIClient(
|
564 |
model_name=model_name,
|
565 |
api_key=access_key,
|
|
|
610 |
elif model_type == ModelType.ChuanhuAgent:
|
611 |
from .ChuanhuAgent import ChuanhuAgent_Client
|
612 |
model = ChuanhuAgent_Client(model_name, access_key, user_name=user_name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
613 |
elif model_type == ModelType.Unknown:
|
614 |
raise ValueError(f"未知模型: {model_name}")
|
615 |
logging.info(msg)
|
616 |
except Exception as e:
|
617 |
+
logging.error(e)
|
|
|
618 |
msg = f"{STANDARD_ERROR_MSG}: {e}"
|
|
|
619 |
if dont_change_lora_selector:
|
620 |
+
return model, msg, chatbot
|
621 |
else:
|
622 |
+
return model, msg, chatbot, gr.Dropdown.update(choices=lora_choices, visible=lora_selector_visibility)
|
623 |
|
624 |
|
625 |
if __name__ == "__main__":
|
modules/overwrites.py
CHANGED
@@ -80,7 +80,8 @@ with open("./assets/custom.js", "r", encoding="utf-8") as f, \
|
|
80 |
def reload_javascript():
|
81 |
print("Reloading javascript...")
|
82 |
js = f'<script>{customJS}</script><script async>{externalScripts}</script>'
|
83 |
-
|
|
|
84 |
def template_response(*args, **kwargs):
|
85 |
res = GradioTemplateResponseOriginal(*args, **kwargs)
|
86 |
res.body = res.body.replace(b'</html>', f'{js}</html>'.encode("utf8"))
|
|
|
80 |
def reload_javascript():
|
81 |
print("Reloading javascript...")
|
82 |
js = f'<script>{customJS}</script><script async>{externalScripts}</script>'
|
83 |
+
# if render_latex:
|
84 |
+
# js += """\"""
|
85 |
def template_response(*args, **kwargs):
|
86 |
res = GradioTemplateResponseOriginal(*args, **kwargs)
|
87 |
res.body = res.body.replace(b'</html>', f'{js}</html>'.encode("utf8"))
|
modules/presets.py
CHANGED
@@ -60,9 +60,7 @@ ONLINE_MODELS = [
|
|
60 |
"gpt-4-32k-0613",
|
61 |
"川虎助理",
|
62 |
"川虎助理 Pro",
|
63 |
-
"GooglePaLM",
|
64 |
"xmchat",
|
65 |
-
"Azure OpenAI",
|
66 |
"yuanai-1.0-base_10B",
|
67 |
"yuanai-1.0-translate",
|
68 |
"yuanai-1.0-dialog",
|
@@ -74,9 +72,7 @@ ONLINE_MODELS = [
|
|
74 |
LOCAL_MODELS = [
|
75 |
"chatglm-6b",
|
76 |
"chatglm-6b-int4",
|
77 |
-
"chatglm-6b-int4-
|
78 |
-
"chatglm2-6b",
|
79 |
-
"chatglm2-6b-int4",
|
80 |
"StableLM",
|
81 |
"MOSS",
|
82 |
"llama-7b-hf",
|
@@ -125,7 +121,6 @@ REPLY_LANGUAGES = [
|
|
125 |
"Español",
|
126 |
"Français",
|
127 |
"Deutsch",
|
128 |
-
"한국어",
|
129 |
"跟随问题语言(不稳定)"
|
130 |
]
|
131 |
|
@@ -227,7 +222,7 @@ small_and_beautiful_theme = gr.themes.Soft(
|
|
227 |
# button_primary_background_fill_hover="*primary_400",
|
228 |
# button_primary_border_color="*primary_500",
|
229 |
button_primary_border_color_dark="*primary_600",
|
230 |
-
button_primary_text_color="
|
231 |
button_primary_text_color_dark="white",
|
232 |
button_secondary_background_fill="*neutral_100",
|
233 |
button_secondary_background_fill_hover="*neutral_50",
|
|
|
60 |
"gpt-4-32k-0613",
|
61 |
"川虎助理",
|
62 |
"川虎助理 Pro",
|
|
|
63 |
"xmchat",
|
|
|
64 |
"yuanai-1.0-base_10B",
|
65 |
"yuanai-1.0-translate",
|
66 |
"yuanai-1.0-dialog",
|
|
|
72 |
LOCAL_MODELS = [
|
73 |
"chatglm-6b",
|
74 |
"chatglm-6b-int4",
|
75 |
+
"chatglm-6b-int4-qe",
|
|
|
|
|
76 |
"StableLM",
|
77 |
"MOSS",
|
78 |
"llama-7b-hf",
|
|
|
121 |
"Español",
|
122 |
"Français",
|
123 |
"Deutsch",
|
|
|
124 |
"跟随问题语言(不稳定)"
|
125 |
]
|
126 |
|
|
|
222 |
# button_primary_background_fill_hover="*primary_400",
|
223 |
# button_primary_border_color="*primary_500",
|
224 |
button_primary_border_color_dark="*primary_600",
|
225 |
+
button_primary_text_color="wihte",
|
226 |
button_primary_text_color_dark="white",
|
227 |
button_secondary_background_fill="*neutral_100",
|
228 |
button_secondary_background_fill_hover="*neutral_50",
|
modules/utils.py
CHANGED
@@ -5,7 +5,6 @@ import logging
|
|
5 |
import json
|
6 |
import os
|
7 |
import datetime
|
8 |
-
from datetime import timezone
|
9 |
import hashlib
|
10 |
import csv
|
11 |
import requests
|
@@ -48,9 +47,6 @@ def set_key(current_model, *args):
|
|
48 |
def load_chat_history(current_model, *args):
|
49 |
return current_model.load_chat_history(*args)
|
50 |
|
51 |
-
def delete_chat_history(current_model, *args):
|
52 |
-
return current_model.delete_chat_history(*args)
|
53 |
-
|
54 |
def interrupt(current_model, *args):
|
55 |
return current_model.interrupt(*args)
|
56 |
|
@@ -218,10 +214,7 @@ def convert_bot_before_marked(chat_message):
|
|
218 |
non_code_parts = code_block_pattern.split(chat_message)[::2]
|
219 |
result = []
|
220 |
|
221 |
-
|
222 |
-
hr_match = re.search(hr_pattern, chat_message, re.DOTALL)
|
223 |
-
clip_hr = chat_message[:hr_match.start()] if hr_match else chat_message
|
224 |
-
raw = f'<div class="raw-message hideM">{escape_markdown(clip_hr)}</div>'
|
225 |
for non_code, code in zip(non_code_parts, code_blocks + [""]):
|
226 |
if non_code.strip():
|
227 |
result.append(non_code)
|
@@ -243,7 +236,7 @@ def escape_markdown(text):
|
|
243 |
Escape Markdown special characters to HTML-safe equivalents.
|
244 |
"""
|
245 |
escape_chars = {
|
246 |
-
|
247 |
'_': '_',
|
248 |
'*': '*',
|
249 |
'[': '[',
|
@@ -260,11 +253,8 @@ def escape_markdown(text):
|
|
260 |
'`': '`',
|
261 |
'>': '>',
|
262 |
'<': '<',
|
263 |
-
'|': '|'
|
264 |
-
'$': '$',
|
265 |
-
':': ':',
|
266 |
}
|
267 |
-
text = text.replace(' ', ' ')
|
268 |
return ''.join(escape_chars.get(c, c) for c in text)
|
269 |
|
270 |
|
@@ -541,55 +531,26 @@ def run(command, desc=None, errdesc=None, custom_env=None, live=False):
|
|
541 |
raise RuntimeError(message)
|
542 |
return result.stdout.decode(encoding="utf8", errors="ignore")
|
543 |
|
544 |
-
def
|
545 |
git = os.environ.get('GIT', "git")
|
|
|
546 |
try:
|
547 |
commit_hash = run(f"{git} rev-parse HEAD").strip()
|
548 |
except Exception:
|
549 |
commit_hash = "<none>"
|
550 |
if commit_hash != "<none>":
|
551 |
short_commit = commit_hash[0:7]
|
552 |
-
commit_info = f
|
553 |
else:
|
554 |
commit_info = "unknown \U0001F615"
|
555 |
-
return commit_info
|
556 |
-
|
557 |
-
def tag_html():
|
558 |
-
git = os.environ.get('GIT', "git")
|
559 |
-
try:
|
560 |
-
tag = run(f"{git} describe --tags --exact-match").strip()
|
561 |
-
except Exception:
|
562 |
-
tag = "<none>"
|
563 |
-
if tag != "<none>":
|
564 |
-
tag_info = f'<a style="text-decoration:none;color:inherit" href="https://github.com/GaiZhenbiao/ChuanhuChatGPT/releases/tag/{tag}">{tag}</a>'
|
565 |
-
else:
|
566 |
-
tag_info = "unknown \U0001F615"
|
567 |
-
return tag_info
|
568 |
-
|
569 |
-
def repo_html():
|
570 |
-
commit_version = commit_html()
|
571 |
-
tag_version = tag_html()
|
572 |
-
return tag_version if tag_version != "unknown \U0001F615" else commit_version
|
573 |
-
|
574 |
-
def versions_html():
|
575 |
-
python_version = ".".join([str(x) for x in sys.version_info[0:3]])
|
576 |
-
repo_version = repo_html()
|
577 |
return f"""
|
578 |
Python: <span title="{sys.version}">{python_version}</span>
|
579 |
•
|
580 |
Gradio: {gr.__version__}
|
581 |
•
|
582 |
-
<a style="text-decoration:none;color:inherit" href="https://github.com/GaiZhenbiao/ChuanhuChatGPT">ChuanhuChat</a>: {
|
583 |
"""
|
584 |
|
585 |
-
def version_time():
|
586 |
-
git = os.environ.get('GIT', "git")
|
587 |
-
try:
|
588 |
-
commit_time = run(f"TZ=UTC {git} log -1 --format=%cd --date='format-local:%Y-%m-%dT%H:%M:%SZ'").strip()
|
589 |
-
except Exception:
|
590 |
-
commit_time = "unknown"
|
591 |
-
return commit_time
|
592 |
-
|
593 |
def get_html(filename):
|
594 |
path = os.path.join(shared.chuanhu_path, "assets", "html", filename)
|
595 |
if os.path.exists(path):
|
|
|
5 |
import json
|
6 |
import os
|
7 |
import datetime
|
|
|
8 |
import hashlib
|
9 |
import csv
|
10 |
import requests
|
|
|
47 |
def load_chat_history(current_model, *args):
|
48 |
return current_model.load_chat_history(*args)
|
49 |
|
|
|
|
|
|
|
50 |
def interrupt(current_model, *args):
|
51 |
return current_model.interrupt(*args)
|
52 |
|
|
|
214 |
non_code_parts = code_block_pattern.split(chat_message)[::2]
|
215 |
result = []
|
216 |
|
217 |
+
raw = f'<div class="raw-message hideM">{escape_markdown(chat_message)}</div>'
|
|
|
|
|
|
|
218 |
for non_code, code in zip(non_code_parts, code_blocks + [""]):
|
219 |
if non_code.strip():
|
220 |
result.append(non_code)
|
|
|
236 |
Escape Markdown special characters to HTML-safe equivalents.
|
237 |
"""
|
238 |
escape_chars = {
|
239 |
+
' ': ' ',
|
240 |
'_': '_',
|
241 |
'*': '*',
|
242 |
'[': '[',
|
|
|
253 |
'`': '`',
|
254 |
'>': '>',
|
255 |
'<': '<',
|
256 |
+
'|': '|'
|
|
|
|
|
257 |
}
|
|
|
258 |
return ''.join(escape_chars.get(c, c) for c in text)
|
259 |
|
260 |
|
|
|
531 |
raise RuntimeError(message)
|
532 |
return result.stdout.decode(encoding="utf8", errors="ignore")
|
533 |
|
534 |
+
def versions_html():
|
535 |
git = os.environ.get('GIT', "git")
|
536 |
+
python_version = ".".join([str(x) for x in sys.version_info[0:3]])
|
537 |
try:
|
538 |
commit_hash = run(f"{git} rev-parse HEAD").strip()
|
539 |
except Exception:
|
540 |
commit_hash = "<none>"
|
541 |
if commit_hash != "<none>":
|
542 |
short_commit = commit_hash[0:7]
|
543 |
+
commit_info = f"<a style=\"text-decoration:none;color:inherit\" href=\"https://github.com/GaiZhenbiao/ChuanhuChatGPT/commit/{short_commit}\">{short_commit}</a>"
|
544 |
else:
|
545 |
commit_info = "unknown \U0001F615"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
546 |
return f"""
|
547 |
Python: <span title="{sys.version}">{python_version}</span>
|
548 |
•
|
549 |
Gradio: {gr.__version__}
|
550 |
•
|
551 |
+
<a style="text-decoration:none;color:inherit" href="https://github.com/GaiZhenbiao/ChuanhuChatGPT">ChuanhuChat</a>: {commit_info}
|
552 |
"""
|
553 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
554 |
def get_html(filename):
|
555 |
path = os.path.join(shared.chuanhu_path, "assets", "html", filename)
|
556 |
if os.path.exists(path):
|
readme/README_en.md
CHANGED
@@ -1,12 +1,12 @@
|
|
1 |
<div align="right">
|
2 |
<!-- Language: -->
|
3 |
-
<a title="Chinese" href="../
|
4 |
</div>
|
5 |
|
6 |
<h1 align="center">川虎 Chat 🐯 Chuanhu Chat</h1>
|
7 |
<div align="center">
|
8 |
<a href="https://github.com/GaiZhenBiao/ChuanhuChatGPT">
|
9 |
-
<img src="https://
|
10 |
</a>
|
11 |
|
12 |
<p align="center">
|
@@ -44,23 +44,6 @@
|
|
44 |
</p>
|
45 |
</div>
|
46 |
|
47 |
-
## Supported LLM Models
|
48 |
-
|
49 |
-
**LLM models via API**:
|
50 |
-
|
51 |
-
- [ChatGPT](https://chat.openai.com) ([GPT-4](https://openai.com/product/gpt-4))
|
52 |
-
- [Google PaLM](https://developers.generativeai.google/products/palm)
|
53 |
-
- [Inspur Yuan 1.0](https://air.inspur.com/home)
|
54 |
-
- [MiniMax](https://api.minimax.chat/)
|
55 |
-
- [XMChat](https://github.com/MILVLG/xmchat)
|
56 |
-
|
57 |
-
**LLM models via local deployment**:
|
58 |
-
|
59 |
-
- [ChatGLM](https://github.com/THUDM/ChatGLM-6B) ([ChatGLM2](https://github.com/THUDM/ChatGLM2-6B))
|
60 |
-
- [LLaMA](https://github.com/facebookresearch/llama)
|
61 |
-
- [StableLM](https://github.com/Stability-AI/StableLM)
|
62 |
-
- [MOSS](https://github.com/OpenLMLab/MOSS)
|
63 |
-
|
64 |
## Usage Tips
|
65 |
|
66 |
- To better control the ChatGPT, use System Prompt.
|
@@ -68,11 +51,11 @@
|
|
68 |
- To try again if the response is unsatisfactory, use `🔄 Regenerate` button.
|
69 |
- To start a new line in the input box, press <kbd>Shift</kbd> + <kbd>Enter</kbd> keys.
|
70 |
- To quickly switch between input history, press <kbd>↑</kbd> and <kbd>↓</kbd> key in the input box.
|
71 |
-
- To deploy the program onto a server,
|
72 |
-
- To get a public shared link,
|
73 |
- To use it in Hugging Face Spaces: It is recommended to **Duplicate Space** and run the program in your own Space for a faster and more secure experience.
|
74 |
|
75 |
-
##
|
76 |
|
77 |
```shell
|
78 |
git clone https://github.com/GaiZhenbiao/ChuanhuChatGPT.git
|
@@ -104,6 +87,10 @@ When you encounter problems, you should try manually pulling the latest changes
|
|
104 |
```
|
105 |
pip install -r requirements.txt
|
106 |
```
|
|
|
|
|
|
|
|
|
107 |
|
108 |
Generally, you can solve most problems by following these steps.
|
109 |
|
|
|
1 |
<div align="right">
|
2 |
<!-- Language: -->
|
3 |
+
<a title="Chinese" href="../README.md">简体中文</a> | English | <a title="Japanese" href="README_ja.md">日本語</a>
|
4 |
</div>
|
5 |
|
6 |
<h1 align="center">川虎 Chat 🐯 Chuanhu Chat</h1>
|
7 |
<div align="center">
|
8 |
<a href="https://github.com/GaiZhenBiao/ChuanhuChatGPT">
|
9 |
+
<img src="https://user-images.githubusercontent.com/70903329/227087087-93b37d64-7dc3-4738-a518-c1cf05591c8a.png" alt="Logo" height="156">
|
10 |
</a>
|
11 |
|
12 |
<p align="center">
|
|
|
44 |
</p>
|
45 |
</div>
|
46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
## Usage Tips
|
48 |
|
49 |
- To better control the ChatGPT, use System Prompt.
|
|
|
51 |
- To try again if the response is unsatisfactory, use `🔄 Regenerate` button.
|
52 |
- To start a new line in the input box, press <kbd>Shift</kbd> + <kbd>Enter</kbd> keys.
|
53 |
- To quickly switch between input history, press <kbd>↑</kbd> and <kbd>↓</kbd> key in the input box.
|
54 |
+
- To deploy the program onto a server, change the last line of the program to `demo.launch(server_name="0.0.0.0", server_port=<your port number>)`.
|
55 |
+
- To get a public shared link, change the last line of the program to `demo.launch(share=True)`. Please be noted that the program must be running in order to be accessed via a public link.
|
56 |
- To use it in Hugging Face Spaces: It is recommended to **Duplicate Space** and run the program in your own Space for a faster and more secure experience.
|
57 |
|
58 |
+
## Installation
|
59 |
|
60 |
```shell
|
61 |
git clone https://github.com/GaiZhenbiao/ChuanhuChatGPT.git
|
|
|
87 |
```
|
88 |
pip install -r requirements.txt
|
89 |
```
|
90 |
+
3. Update Gradio
|
91 |
+
```
|
92 |
+
pip install gradio --upgrade --force-reinstall
|
93 |
+
```
|
94 |
|
95 |
Generally, you can solve most problems by following these steps.
|
96 |
|
readme/README_ja.md
CHANGED
@@ -1,12 +1,12 @@
|
|
1 |
<div align="right">
|
2 |
<!-- Language: -->
|
3 |
-
<a title="Chinese" href="../
|
4 |
</div>
|
5 |
|
6 |
<h1 align="center">川虎 Chat 🐯 Chuanhu Chat</h1>
|
7 |
<div align="center">
|
8 |
<a href="https://github.com/GaiZhenBiao/ChuanhuChatGPT">
|
9 |
-
<img src="https://
|
10 |
</a>
|
11 |
|
12 |
<p align="center">
|
@@ -44,34 +44,17 @@
|
|
44 |
</p>
|
45 |
</div>
|
46 |
|
47 |
-
## サポートされている大規模言語モデル
|
48 |
-
|
49 |
-
**APIを通じてアクセス可能な大規模言語モデル**:
|
50 |
-
|
51 |
-
- [ChatGPT](https://chat.openai.com) ([GPT-4](https://openai.com/product/gpt-4))
|
52 |
-
- [Google PaLM](https://developers.generativeai.google/products/palm)
|
53 |
-
- [Inspur Yuan 1.0](https://air.inspur.com/home)
|
54 |
-
- [MiniMax](https://api.minimax.chat/)
|
55 |
-
- [XMChat](https://github.com/MILVLG/xmchat)
|
56 |
-
|
57 |
-
**ローカルに展開された大規模言語モデル**:
|
58 |
-
|
59 |
-
- [ChatGLM](https://github.com/THUDM/ChatGLM-6B) ([ChatGLM2](https://github.com/THUDM/ChatGLM2-6B))
|
60 |
-
- [LLaMA](https://github.com/facebookresearch/llama)
|
61 |
-
- [StableLM](https://github.com/Stability-AI/StableLM)
|
62 |
-
- [MOSS](https://github.com/OpenLMLab/MOSS)
|
63 |
-
|
64 |
## 使う上でのTips
|
65 |
|
66 |
- ChatGPTをより適切に制御するために、システムプロンプトを使用できます。
|
67 |
- プロンプトテンプレートを使用するには、プロンプトテンプレートコレクションを選択し、ドロップダウンメニューから特定のプロンプトを選択。回答が不十分な場合は、`🔄再生成`ボタンを使って再試行します。
|
68 |
- 入力ボックスで改行するには、<kbd>Shift</kbd> + <kbd>Enter</kbd>キーを押してください。
|
69 |
- 入力履歴を素早く切り替えるには、入力ボックスで <kbd>↑</kbd>と<kbd>↓</kbd>キーを押す。
|
70 |
-
-
|
71 |
-
-
|
72 |
- Hugging Face Spacesで使用する場合: より速く、より安全に利用するために、**Duplicate Space**を使用し、自分のスペースでプログラムを実行することをお勧めします。
|
73 |
|
74 |
-
##
|
75 |
|
76 |
```shell
|
77 |
git clone https://github.com/GaiZhenbiao/ChuanhuChatGPT.git
|
@@ -103,6 +86,10 @@ python ChuanhuChatbot.py
|
|
103 |
```
|
104 |
pip install -r requirements.txt
|
105 |
```
|
|
|
|
|
|
|
|
|
106 |
|
107 |
一般的に、以下の手順でほとんどの問題を解決することができます。
|
108 |
|
|
|
1 |
<div align="right">
|
2 |
<!-- Language: -->
|
3 |
+
<a title="Chinese" href="../README.md">简体中文</a> | <a title="English" href="README_en.md">English</a> | 日本語
|
4 |
</div>
|
5 |
|
6 |
<h1 align="center">川虎 Chat 🐯 Chuanhu Chat</h1>
|
7 |
<div align="center">
|
8 |
<a href="https://github.com/GaiZhenBiao/ChuanhuChatGPT">
|
9 |
+
<img src="https://user-images.githubusercontent.com/70903329/227087087-93b37d64-7dc3-4738-a518-c1cf05591c8a.png" alt="Logo" height="156">
|
10 |
</a>
|
11 |
|
12 |
<p align="center">
|
|
|
44 |
</p>
|
45 |
</div>
|
46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
## 使う上でのTips
|
48 |
|
49 |
- ChatGPTをより適切に制御するために、システムプロンプトを使用できます。
|
50 |
- プロンプトテンプレートを使用するには、プロンプトテンプレートコレクションを選択し、ドロップダウンメニューから特定のプロンプトを選択。回答が不十分な場合は、`🔄再生成`ボタンを使って再試行します。
|
51 |
- 入力ボックスで改行するには、<kbd>Shift</kbd> + <kbd>Enter</kbd>キーを押してください。
|
52 |
- 入力履歴を素早く切り替えるには、入力ボックスで <kbd>↑</kbd>と<kbd>↓</kbd>キーを押す。
|
53 |
+
- プログラムをサーバにデプロイするには、プログラムの最終行を `demo.launch(server_name="0.0.0.0", server_port=<your port number>)`に変更します。
|
54 |
+
- 共有リンクを取得するには、プログラムの最後の行を `demo.launch(share=True)` に変更してください。なお、公開リンクでアクセスするためには、プログラムが実行されている必要があることに注意してください。
|
55 |
- Hugging Face Spacesで使用する場合: より速く、より安全に利用するために、**Duplicate Space**を使用し、自分のスペースでプログラムを実行することをお勧めします。
|
56 |
|
57 |
+
## インストール
|
58 |
|
59 |
```shell
|
60 |
git clone https://github.com/GaiZhenbiao/ChuanhuChatGPT.git
|
|
|
86 |
```
|
87 |
pip install -r requirements.txt
|
88 |
```
|
89 |
+
3. Gradioを更新
|
90 |
+
```
|
91 |
+
pip install gradio --upgrade --force-reinstall
|
92 |
+
```
|
93 |
|
94 |
一般的に、以下の手順でほとんどの問題を解決することができます。
|
95 |
|
requirements.txt
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
-
gradio==3.
|
2 |
-
gradio_client==0.2.
|
3 |
pypinyin
|
4 |
tiktoken
|
5 |
socksio
|
@@ -16,12 +16,10 @@ commentjson
|
|
16 |
openpyxl
|
17 |
pandoc
|
18 |
wolframalpha
|
19 |
-
faiss-cpu
|
20 |
duckduckgo-search
|
21 |
arxiv
|
22 |
wikipedia
|
23 |
google.generativeai
|
24 |
openai
|
25 |
unstructured
|
26 |
-
google-api-python-client
|
27 |
-
tabulate
|
|
|
1 |
+
gradio==3.33.1
|
2 |
+
gradio_client==0.2.5
|
3 |
pypinyin
|
4 |
tiktoken
|
5 |
socksio
|
|
|
16 |
openpyxl
|
17 |
pandoc
|
18 |
wolframalpha
|
19 |
+
faiss-cpu
|
20 |
duckduckgo-search
|
21 |
arxiv
|
22 |
wikipedia
|
23 |
google.generativeai
|
24 |
openai
|
25 |
unstructured
|
|
|
|
requirements_advanced.txt
DELETED
@@ -1,11 +0,0 @@
|
|
1 |
-
transformers
|
2 |
-
huggingface_hub
|
3 |
-
torch
|
4 |
-
icetk
|
5 |
-
protobuf==3.19.0
|
6 |
-
git+https://github.com/OptimalScale/LMFlow.git
|
7 |
-
cpm-kernels
|
8 |
-
sentence_transformers
|
9 |
-
accelerate
|
10 |
-
sentencepiece
|
11 |
-
datasets
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
run_Windows.bat
CHANGED
@@ -1,24 +1,5 @@
|
|
1 |
@echo off
|
2 |
echo Opening ChuanhuChatGPT...
|
3 |
|
4 |
-
|
5 |
-
|
6 |
-
python -m venv ChuanhuChat
|
7 |
-
|
8 |
-
cd /d "%~dp0\ChuanhuChat\Scripts"
|
9 |
-
call activate.bat
|
10 |
-
|
11 |
-
cd /d "%~dp0"
|
12 |
-
pip install -r requirements.txt
|
13 |
-
)
|
14 |
-
|
15 |
-
goto :activate_venv
|
16 |
-
|
17 |
-
:launch
|
18 |
-
%PYTHON% ChuanhuChatbot.py %*
|
19 |
-
pause
|
20 |
-
|
21 |
-
:activate_venv
|
22 |
-
set PYTHON="%~dp0\ChuanhuChat\Scripts\Python.exe"
|
23 |
-
echo venv %PYTHON%
|
24 |
-
goto :launch
|
|
|
1 |
@echo off
|
2 |
echo Opening ChuanhuChatGPT...
|
3 |
|
4 |
+
REM Open powershell via bat
|
5 |
+
start powershell.exe -NoExit -Command "python ./ChuanhuChatbot.py"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|