Spaces:
Sleeping
Sleeping
JohnSmith9982
commited on
Commit
•
79eae90
1
Parent(s):
b74ce33
Upload 97 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- ChuanhuChatbot.py +555 -307
- config_example.json +15 -8
- locale/en_US.json +126 -72
- locale/extract_locale.py +132 -20
- locale/ja_JP.json +126 -72
- locale/ko_KR.json +126 -74
- locale/ru_RU.json +141 -0
- locale/sv_SE.json +141 -0
- locale/vi_VN.json +141 -0
- locale/zh_CN.json +1 -0
- modules/config.py +26 -6
- modules/index_func.py +6 -3
- modules/models/Azure.py +18 -0
- modules/models/ChatGLM.py +84 -0
- modules/models/ChuanhuAgent.py +18 -2
- modules/models/Claude.py +55 -0
- modules/models/GooglePaLM.py +29 -0
- modules/models/LLaMA.py +126 -0
- modules/models/OpenAI.py +279 -0
- modules/models/OpenAIInstruct.py +27 -0
- modules/models/OpenAIVision.py +328 -0
- modules/models/Qwen.py +57 -0
- modules/models/XMChat.py +149 -0
- modules/models/base_model.py +178 -79
- modules/models/midjourney.py +6 -7
- modules/models/models.py +49 -543
- modules/models/spark.py +166 -0
- modules/overwrites.py +29 -26
- modules/presets.py +97 -31
- modules/repo.py +129 -42
- modules/shared.py +7 -5
- modules/utils.py +105 -62
- modules/webui.py +14 -1
- modules/webui_locale.py +9 -2
- readme/README_en.md +86 -36
- readme/README_ja.md +76 -28
- readme/README_ru.md +186 -0
- requirements.txt +10 -5
- requirements_advanced.txt +5 -4
- templates/6 Russian Prompts.json +0 -0
- web_assets/.DS_Store +0 -0
- web_assets/html/chatbot_header_btn.html +72 -0
- web_assets/html/chatbot_more.html +72 -0
- web_assets/html/close_btn.html +5 -0
- web_assets/html/func_nav.html +78 -0
- web_assets/html/header_title.html +20 -0
- web_assets/html/web_config.html +21 -0
- web_assets/icon/any-icon-512.png +0 -0
- web_assets/icon/mask-icon-512.png +0 -0
- web_assets/javascript/ChuanhuChat.js +231 -99
ChuanhuChatbot.py
CHANGED
@@ -5,18 +5,18 @@ logging.basicConfig(
|
|
5 |
format="%(asctime)s [%(levelname)s] [%(filename)s:%(lineno)d] %(message)s",
|
6 |
)
|
7 |
|
8 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
import gradio as gr
|
|
|
10 |
|
11 |
-
from modules import config
|
12 |
-
from modules.config import *
|
13 |
-
from modules.utils import *
|
14 |
-
from modules.presets import *
|
15 |
-
from modules.overwrites import *
|
16 |
-
from modules.webui import *
|
17 |
-
from modules.repo import *
|
18 |
-
from modules.train_func import *
|
19 |
-
from modules.models.models import get_model
|
20 |
|
21 |
logging.getLogger("httpx").setLevel(logging.WARNING)
|
22 |
|
@@ -26,25 +26,28 @@ gr.Chatbot.postprocess = postprocess
|
|
26 |
# with open("web_assets/css/ChuanhuChat.css", "r", encoding="utf-8") as f:
|
27 |
# ChuanhuChatCSS = f.read()
|
28 |
|
|
|
29 |
def create_new_model():
|
30 |
-
return get_model(model_name
|
|
|
31 |
|
32 |
with gr.Blocks(theme=small_and_beautiful_theme) as demo:
|
33 |
-
user_name = gr.
|
34 |
-
promptTemplates = gr.State(load_template(get_template_names(
|
35 |
user_question = gr.State("")
|
36 |
-
assert type(my_api_key)==str
|
37 |
user_api_key = gr.State(my_api_key)
|
38 |
-
current_model = gr.State(
|
39 |
|
40 |
topic = gr.State(i18n("未命名对话历史记录"))
|
41 |
|
42 |
-
with gr.Row():
|
43 |
-
gr.HTML(
|
|
|
44 |
status_display = gr.Markdown(get_geoip(), elem_id="status-display")
|
45 |
with gr.Row(elem_id="float-display"):
|
46 |
-
user_info = gr.Markdown(
|
47 |
-
|
48 |
update_info = gr.HTML(get_html("update.html").format(
|
49 |
current_version=repo_tag_html(),
|
50 |
version_time=version_time(),
|
@@ -52,248 +55,339 @@ with gr.Blocks(theme=small_and_beautiful_theme) as demo:
|
|
52 |
update_btn=i18n("更新"),
|
53 |
seenew_btn=i18n("详情"),
|
54 |
ok_btn=i18n("好"),
|
55 |
-
|
56 |
-
|
57 |
-
with gr.Row(equal_height=True):
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
model_select_dropdown = gr.Dropdown(
|
104 |
-
label=i18n("选择模型"), choices=MODELS, multiselect=False, value=MODELS[DEFAULT_MODEL], interactive=True
|
|
|
105 |
)
|
106 |
lora_select_dropdown = gr.Dropdown(
|
107 |
-
label=i18n("选择LoRA模型"), choices=[], multiselect=False, interactive=True, visible=False
|
|
|
108 |
)
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
|
|
|
|
|
|
|
|
|
|
117 |
)
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
label=i18n("选择Prompt模板集合文件"),
|
138 |
-
choices=get_template_names(plain=True),
|
139 |
-
multiselect=False,
|
140 |
-
value=get_template_names(plain=True)[0],
|
141 |
-
container=False,
|
142 |
-
)
|
143 |
-
with gr.Column(scale=1):
|
144 |
-
templateRefreshBtn = gr.Button(i18n("🔄 刷新"))
|
145 |
-
with gr.Row():
|
146 |
-
with gr.Column():
|
147 |
-
templateSelectDropdown = gr.Dropdown(
|
148 |
-
label=i18n("从Prompt模板中加载"),
|
149 |
-
choices=load_template(
|
150 |
-
get_template_names(plain=True)[0], mode=1
|
151 |
-
),
|
152 |
-
multiselect=False,
|
153 |
-
container=False,
|
154 |
-
)
|
155 |
-
|
156 |
-
with gr.Tab(label=i18n("保存/加载")):
|
157 |
-
with gr.Accordion(label=i18n("保存/加载对话历史记录"), open=True):
|
158 |
-
with gr.Column():
|
159 |
-
with gr.Row():
|
160 |
-
with gr.Column(scale=6):
|
161 |
-
historyFileSelectDropdown = gr.Dropdown(
|
162 |
-
label=i18n("从列表中加载对话"),
|
163 |
-
choices=get_history_names(plain=True),
|
164 |
-
multiselect=False,
|
165 |
-
container=False,
|
166 |
)
|
167 |
-
with gr.
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
with gr.Row():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
187 |
with gr.Column():
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
)
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
242 |
show_label=True,
|
243 |
-
placeholder=
|
244 |
-
|
245 |
-
|
246 |
-
|
|
|
247 |
)
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
255 |
)
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
label="max generations",
|
263 |
-
)
|
264 |
-
presence_penalty_slider = gr.Slider(
|
265 |
-
minimum=-2.0,
|
266 |
-
maximum=2.0,
|
267 |
-
value=0.0,
|
268 |
-
step=0.01,
|
269 |
-
interactive=True,
|
270 |
-
label="presence penalty",
|
271 |
)
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
step=0.01,
|
277 |
interactive=True,
|
278 |
-
|
279 |
-
)
|
280 |
-
logit_bias_txt = gr.Textbox(
|
281 |
-
show_label=True,
|
282 |
-
placeholder=f"word:likelihood",
|
283 |
-
label="logit bias",
|
284 |
-
value="",
|
285 |
-
lines=1,
|
286 |
-
)
|
287 |
-
user_identifier_txt = gr.Textbox(
|
288 |
-
show_label=True,
|
289 |
-
placeholder=i18n("用于定位滥用行为"),
|
290 |
-
label=i18n("用户名"),
|
291 |
-
value=user_name.value,
|
292 |
-
lines=1,
|
293 |
)
|
|
|
|
|
|
|
294 |
|
295 |
-
with gr.
|
296 |
-
gr.Markdown(
|
|
|
297 |
default_btn = gr.Button(i18n("🔙 恢复默认网络设置"))
|
298 |
# 网络代理
|
299 |
proxyTxt = gr.Textbox(
|
@@ -319,25 +413,99 @@ with gr.Blocks(theme=small_and_beautiful_theme) as demo:
|
|
319 |
# container=False,
|
320 |
elem_classes="view-only-textbox no-container",
|
321 |
)
|
322 |
-
# changeAPIURLBtn = gr.Button(i18n("🔄 切换API地址"))
|
323 |
-
updateChuanhuBtn = gr.Button(visible=False, elem_classes="invisible-btn", elem_id="update-chuanhu-btn")
|
324 |
|
325 |
-
|
326 |
-
|
327 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
328 |
|
329 |
# https://github.com/gradio-app/gradio/pull/3296
|
|
|
330 |
def create_greeting(request: gr.Request):
|
331 |
-
if hasattr(request, "username") and request.username:
|
332 |
logging.info(f"Get User Name: {request.username}")
|
333 |
-
user_info, user_name = gr.Markdown.update(
|
|
|
334 |
else:
|
335 |
-
user_info, user_name = gr.Markdown.update(
|
336 |
-
|
|
|
|
|
337 |
current_model.set_user_identifier(user_name)
|
338 |
-
|
339 |
-
|
340 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
341 |
chatgpt_predict_args = dict(
|
342 |
fn=predict,
|
343 |
inputs=[
|
@@ -369,42 +537,58 @@ with gr.Blocks(theme=small_and_beautiful_theme) as demo:
|
|
369 |
)
|
370 |
|
371 |
transfer_input_args = dict(
|
372 |
-
fn=transfer_input, inputs=[user_input], outputs=[
|
|
|
373 |
)
|
374 |
|
375 |
get_usage_args = dict(
|
376 |
-
fn=billing_info, inputs=[current_model], outputs=[
|
|
|
377 |
)
|
378 |
|
379 |
load_history_from_file_args = dict(
|
380 |
fn=load_chat_history,
|
381 |
-
inputs=[current_model,
|
382 |
outputs=[saveFileName, systemPromptTxt, chatbot]
|
383 |
)
|
384 |
|
385 |
refresh_history_args = dict(
|
386 |
-
fn=
|
387 |
)
|
388 |
|
|
|
|
|
|
|
|
|
|
|
|
|
389 |
|
390 |
# Chatbot
|
391 |
cancelBtn.click(interrupt, [current_model], [])
|
392 |
|
393 |
-
user_input.submit(**transfer_input_args).then(**
|
|
|
394 |
user_input.submit(**get_usage_args)
|
395 |
|
396 |
-
|
|
|
|
|
|
|
397 |
submitBtn.click(**get_usage_args)
|
398 |
|
399 |
-
|
400 |
-
|
|
|
|
|
|
|
|
|
401 |
|
402 |
emptyBtn.click(
|
403 |
reset,
|
404 |
-
inputs=[current_model],
|
405 |
-
outputs=[chatbot, status_display],
|
406 |
show_progress=True,
|
407 |
-
_js='clearChatbot',
|
408 |
)
|
409 |
|
410 |
retryBtn.click(**start_outputing_args).then(
|
@@ -452,17 +636,24 @@ with gr.Blocks(theme=small_and_beautiful_theme) as demo:
|
|
452 |
two_column.change(update_doc_config, [two_column], None)
|
453 |
|
454 |
# LLM Models
|
455 |
-
keyTxt.change(set_key, [current_model, keyTxt], [
|
|
|
456 |
keyTxt.submit(**get_usage_args)
|
457 |
-
single_turn_checkbox.change(
|
458 |
-
|
459 |
-
model_select_dropdown.change(
|
460 |
-
|
|
|
|
|
|
|
|
|
461 |
|
462 |
# Template
|
463 |
-
systemPromptTxt.change(set_system_prompt, [
|
464 |
-
|
465 |
-
|
|
|
|
|
466 |
load_template,
|
467 |
[templateFileSelectDropdown],
|
468 |
[promptTemplates, templateSelectDropdown],
|
@@ -476,47 +667,80 @@ with gr.Blocks(theme=small_and_beautiful_theme) as demo:
|
|
476 |
)
|
477 |
|
478 |
# S&L
|
479 |
-
|
480 |
-
|
481 |
[current_model, saveFileName, chatbot, user_name],
|
482 |
-
|
483 |
show_progress=True,
|
|
|
484 |
)
|
485 |
-
saveHistoryBtn.click(get_history_names, [gr.State(False), user_name], [historyFileSelectDropdown])
|
486 |
exportMarkdownBtn.click(
|
487 |
export_markdown,
|
488 |
[current_model, saveFileName, chatbot, user_name],
|
489 |
-
|
490 |
show_progress=True,
|
491 |
)
|
492 |
historyRefreshBtn.click(**refresh_history_args)
|
493 |
-
historyDeleteBtn.click(delete_chat_history, [current_model,
|
494 |
-
|
495 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
496 |
|
497 |
# Train
|
498 |
-
dataset_selection.upload(handle_dataset_selection, dataset_selection, [
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
508 |
|
509 |
# Advanced
|
510 |
-
max_context_length_slider.change(
|
511 |
-
|
|
|
|
|
512 |
top_p_slider.change(set_top_p, [current_model, top_p_slider], None)
|
513 |
-
n_choices_slider.change(
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
520 |
|
521 |
default_btn.click(
|
522 |
reset_default, [], [apihostTxt, proxyTxt, status_display], show_progress=True
|
@@ -533,7 +757,7 @@ with gr.Blocks(theme=small_and_beautiful_theme) as demo:
|
|
533 |
# [status_display],
|
534 |
# show_progress=True,
|
535 |
# )
|
536 |
-
checkUpdateBtn.click(fn=None, _js='manualCheckUpdate')
|
537 |
|
538 |
# Invisible elements
|
539 |
updateChuanhuBtn.click(
|
@@ -542,6 +766,25 @@ with gr.Blocks(theme=small_and_beautiful_theme) as demo:
|
|
542 |
[status_display],
|
543 |
show_progress=True,
|
544 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
545 |
|
546 |
logging.info(
|
547 |
colorama.Back.GREEN
|
@@ -554,6 +797,11 @@ demo.title = i18n("川虎Chat 🚀")
|
|
554 |
if __name__ == "__main__":
|
555 |
reload_javascript()
|
556 |
demo.queue(concurrency_count=CONCURRENT_COUNT).launch(
|
557 |
-
|
|
|
|
|
|
|
|
|
558 |
favicon_path="./web_assets/favicon.ico",
|
|
|
559 |
)
|
|
|
5 |
format="%(asctime)s [%(levelname)s] [%(filename)s:%(lineno)d] %(message)s",
|
6 |
)
|
7 |
|
8 |
+
from modules.models.models import get_model
|
9 |
+
from modules.train_func import *
|
10 |
+
from modules.repo import *
|
11 |
+
from modules.webui import *
|
12 |
+
from modules.overwrites import *
|
13 |
+
from modules.presets import *
|
14 |
+
from modules.utils import *
|
15 |
+
from modules.config import *
|
16 |
+
from modules import config
|
17 |
import gradio as gr
|
18 |
+
import colorama
|
19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
logging.getLogger("httpx").setLevel(logging.WARNING)
|
22 |
|
|
|
26 |
# with open("web_assets/css/ChuanhuChat.css", "r", encoding="utf-8") as f:
|
27 |
# ChuanhuChatCSS = f.read()
|
28 |
|
29 |
+
|
30 |
def create_new_model():
|
31 |
+
return get_model(model_name=MODELS[DEFAULT_MODEL], access_key=my_api_key)[0]
|
32 |
+
|
33 |
|
34 |
with gr.Blocks(theme=small_and_beautiful_theme) as demo:
|
35 |
+
user_name = gr.Textbox("", visible=False)
|
36 |
+
promptTemplates = gr.State(load_template(get_template_names()[0], mode=2))
|
37 |
user_question = gr.State("")
|
38 |
+
assert type(my_api_key) == str
|
39 |
user_api_key = gr.State(my_api_key)
|
40 |
+
current_model = gr.State()
|
41 |
|
42 |
topic = gr.State(i18n("未命名对话历史记录"))
|
43 |
|
44 |
+
with gr.Row(elem_id="chuanhu-header"):
|
45 |
+
gr.HTML(get_html("header_title.html").format(
|
46 |
+
app_title=CHUANHU_TITLE), elem_id="app-title")
|
47 |
status_display = gr.Markdown(get_geoip(), elem_id="status-display")
|
48 |
with gr.Row(elem_id="float-display"):
|
49 |
+
user_info = gr.Markdown(
|
50 |
+
value="getting user info...", elem_id="user-info")
|
51 |
update_info = gr.HTML(get_html("update.html").format(
|
52 |
current_version=repo_tag_html(),
|
53 |
version_time=version_time(),
|
|
|
55 |
update_btn=i18n("更新"),
|
56 |
seenew_btn=i18n("详情"),
|
57 |
ok_btn=i18n("好"),
|
58 |
+
), visible=check_update)
|
59 |
+
|
60 |
+
with gr.Row(equal_height=True, elem_id="chuanhu-body"):
|
61 |
+
|
62 |
+
with gr.Column(elem_id="menu-area"):
|
63 |
+
with gr.Column(elem_id="chuanhu-history"):
|
64 |
+
with gr.Box():
|
65 |
+
with gr.Row(elem_id="chuanhu-history-header"):
|
66 |
+
with gr.Row(elem_id="chuanhu-history-search-row"):
|
67 |
+
with gr.Column(min_width=150, scale=2):
|
68 |
+
historySearchTextbox = gr.Textbox(show_label=False, container=False, placeholder=i18n(
|
69 |
+
"搜索(支持正则)..."), lines=1, elem_id="history-search-tb")
|
70 |
+
with gr.Column(min_width=52, scale=1, elem_id="gr-history-header-btns"):
|
71 |
+
uploadFileBtn = gr.UploadButton(
|
72 |
+
interactive=True, label="", file_types=[".json"], elem_id="gr-history-upload-btn")
|
73 |
+
historyRefreshBtn = gr.Button("", elem_id="gr-history-refresh-btn")
|
74 |
+
|
75 |
+
|
76 |
+
with gr.Row(elem_id="chuanhu-history-body"):
|
77 |
+
with gr.Column(scale=6, elem_id="history-select-wrap"):
|
78 |
+
historySelectList = gr.Radio(
|
79 |
+
label=i18n("从列表中加载对话"),
|
80 |
+
choices=get_history_names(),
|
81 |
+
value=get_first_history_name(),
|
82 |
+
# multiselect=False,
|
83 |
+
container=False,
|
84 |
+
elem_id="history-select-dropdown"
|
85 |
+
)
|
86 |
+
with gr.Row(visible=False):
|
87 |
+
with gr.Column(min_width=42, scale=1):
|
88 |
+
historyDeleteBtn = gr.Button(
|
89 |
+
"🗑️", elem_id="gr-history-delete-btn")
|
90 |
+
with gr.Column(min_width=42, scale=1):
|
91 |
+
historyDownloadBtn = gr.Button(
|
92 |
+
"⏬", elem_id="gr-history-download-btn")
|
93 |
+
with gr.Column(min_width=42, scale=1):
|
94 |
+
historyMarkdownDownloadBtn = gr.Button(
|
95 |
+
"⤵️", elem_id="gr-history-mardown-download-btn")
|
96 |
+
with gr.Row(visible=False):
|
97 |
+
with gr.Column(scale=6):
|
98 |
+
saveFileName = gr.Textbox(
|
99 |
+
show_label=True,
|
100 |
+
placeholder=i18n("设置文件名: 默认为.json,可选为.md"),
|
101 |
+
label=i18n("设置保存文件名"),
|
102 |
+
value=i18n("对话历史记录"),
|
103 |
+
elem_classes="no-container"
|
104 |
+
# container=False,
|
105 |
+
)
|
106 |
+
with gr.Column(scale=1):
|
107 |
+
renameHistoryBtn = gr.Button(
|
108 |
+
i18n("💾 保存对话"), elem_id="gr-history-save-btn")
|
109 |
+
exportMarkdownBtn = gr.Button(
|
110 |
+
i18n("📝 导出为 Markdown"), elem_id="gr-markdown-export-btn")
|
111 |
+
|
112 |
+
with gr.Column(elem_id="chuanhu-menu-footer"):
|
113 |
+
with gr.Row(elem_id="chuanhu-func-nav"):
|
114 |
+
gr.HTML(get_html("func_nav.html"))
|
115 |
+
# gr.HTML(get_html("footer.html").format(versions=versions_html()), elem_id="footer")
|
116 |
+
# gr.Markdown(CHUANHU_DESCRIPTION, elem_id="chuanhu-author")
|
117 |
+
|
118 |
+
with gr.Column(elem_id="chuanhu-area", scale=5):
|
119 |
+
with gr.Column(elem_id="chatbot-area"):
|
120 |
+
with gr.Row(elem_id="chatbot-header"):
|
121 |
model_select_dropdown = gr.Dropdown(
|
122 |
+
label=i18n("选择模型"), choices=MODELS, multiselect=False, value=MODELS[DEFAULT_MODEL], interactive=True,
|
123 |
+
show_label=False, container=False, elem_id="model-select-dropdown"
|
124 |
)
|
125 |
lora_select_dropdown = gr.Dropdown(
|
126 |
+
label=i18n("选择LoRA模型"), choices=[], multiselect=False, interactive=True, visible=False,
|
127 |
+
container=False,
|
128 |
)
|
129 |
+
gr.HTML(get_html("chatbot_header_btn.html").format(
|
130 |
+
json_label=i18n("历史记录(JSON)"),
|
131 |
+
md_label=i18n("导出为 Markdown")
|
132 |
+
), elem_id="chatbot-header-btn-bar")
|
133 |
+
with gr.Row():
|
134 |
+
chatbot = gr.Chatbot(
|
135 |
+
label="Chuanhu Chat",
|
136 |
+
elem_id="chuanhu-chatbot",
|
137 |
+
latex_delimiters=latex_delimiters_set,
|
138 |
+
# height=700,
|
139 |
+
show_label=False,
|
140 |
+
avatar_images=[config.user_avatar, config.bot_avatar],
|
141 |
+
show_share_button=False,
|
142 |
)
|
143 |
+
with gr.Row(elem_id="chatbot-footer"):
|
144 |
+
with gr.Box(elem_id="chatbot-input-box"):
|
145 |
+
with gr.Row(elem_id="chatbot-input-row"):
|
146 |
+
gr.HTML(get_html("chatbot_more.html").format(
|
147 |
+
single_turn_label=i18n("单轮对话"),
|
148 |
+
websearch_label=i18n("在线搜索"),
|
149 |
+
upload_file_label=i18n("上传文件"),
|
150 |
+
uploaded_files_label=i18n("知识库文件"),
|
151 |
+
uploaded_files_tip=i18n("在工具箱中管理知识库文件")
|
152 |
+
))
|
153 |
+
with gr.Row(elem_id="chatbot-input-tb-row"):
|
154 |
+
with gr.Column(min_width=225, scale=12):
|
155 |
+
user_input = gr.Textbox(
|
156 |
+
elem_id="user-input-tb",
|
157 |
+
show_label=False,
|
158 |
+
placeholder=i18n("在这里输入"),
|
159 |
+
elem_classes="no-container",
|
160 |
+
max_lines=5,
|
161 |
+
# container=False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
162 |
)
|
163 |
+
with gr.Column(min_width=42, scale=1, elem_id="chatbot-ctrl-btns"):
|
164 |
+
submitBtn = gr.Button(
|
165 |
+
value="", variant="primary", elem_id="submit-btn")
|
166 |
+
cancelBtn = gr.Button(
|
167 |
+
value="", variant="secondary", visible=False, elem_id="cancel-btn")
|
168 |
+
# Note: Buttons below are set invisible in UI. But they are used in JS.
|
169 |
+
with gr.Row(elem_id="chatbot-buttons", visible=False):
|
170 |
+
with gr.Column(min_width=120, scale=1):
|
171 |
+
emptyBtn = gr.Button(
|
172 |
+
i18n("🧹 新的对话"), elem_id="empty-btn"
|
173 |
+
)
|
174 |
+
with gr.Column(min_width=120, scale=1):
|
175 |
+
retryBtn = gr.Button(
|
176 |
+
i18n("🔄 重新生成"), elem_id="gr-retry-btn")
|
177 |
+
with gr.Column(min_width=120, scale=1):
|
178 |
+
delFirstBtn = gr.Button(i18n("🗑️ 删除最旧对话"))
|
179 |
+
with gr.Column(min_width=120, scale=1):
|
180 |
+
delLastBtn = gr.Button(
|
181 |
+
i18n("🗑️ 删除最新对话"), elem_id="gr-dellast-btn")
|
182 |
+
with gr.Row(visible=False) as like_dislike_area:
|
183 |
+
with gr.Column(min_width=20, scale=1):
|
184 |
+
likeBtn = gr.Button(
|
185 |
+
"👍", elem_id="gr-like-btn")
|
186 |
+
with gr.Column(min_width=20, scale=1):
|
187 |
+
dislikeBtn = gr.Button(
|
188 |
+
"👎", elem_id="gr-dislike-btn")
|
189 |
+
|
190 |
+
with gr.Column(elem_id="toolbox-area", scale=1):
|
191 |
+
# For CSS setting, there is an extra box. Don't remove it.
|
192 |
+
with gr.Box(elem_id="chuanhu-toolbox"):
|
193 |
+
with gr.Row():
|
194 |
+
gr.Markdown("## "+i18n("工具箱"))
|
195 |
+
gr.HTML(get_html("close_btn.html").format(
|
196 |
+
obj="toolbox"), elem_classes="close-btn")
|
197 |
+
with gr.Tabs(elem_id="chuanhu-toolbox-tabs"):
|
198 |
+
with gr.Tab(label=i18n("对话")):
|
199 |
+
with gr.Accordion(label="Prompt", open=True):
|
200 |
+
systemPromptTxt = gr.Textbox(
|
201 |
+
show_label=True,
|
202 |
+
placeholder=i18n("在这里输入System Prompt..."),
|
203 |
+
label="System prompt",
|
204 |
+
value=INITIAL_SYSTEM_PROMPT,
|
205 |
+
lines=8
|
206 |
+
)
|
207 |
+
retain_system_prompt_checkbox = gr.Checkbox(
|
208 |
+
label=i18n("新建对话保留Prompt"), value=False, visible=True, elem_classes="switch-checkbox")
|
209 |
+
with gr.Accordion(label=i18n("加载Prompt模板"), open=False):
|
210 |
with gr.Column():
|
211 |
+
with gr.Row():
|
212 |
+
with gr.Column(scale=6):
|
213 |
+
templateFileSelectDropdown = gr.Dropdown(
|
214 |
+
label=i18n("选择Prompt模板集合文件"),
|
215 |
+
choices=get_template_names(),
|
216 |
+
multiselect=False,
|
217 |
+
value=get_template_names()[0],
|
218 |
+
container=False,
|
219 |
+
)
|
220 |
+
with gr.Column(scale=1):
|
221 |
+
templateRefreshBtn = gr.Button(
|
222 |
+
i18n("🔄 刷新"))
|
223 |
+
with gr.Row():
|
224 |
+
with gr.Column():
|
225 |
+
templateSelectDropdown = gr.Dropdown(
|
226 |
+
label=i18n("从Prompt模板中加载"),
|
227 |
+
choices=load_template(
|
228 |
+
get_template_names()[
|
229 |
+
0], mode=1
|
230 |
+
),
|
231 |
+
multiselect=False,
|
232 |
+
container=False,
|
233 |
+
)
|
234 |
+
gr.Markdown("---", elem_classes="hr-line")
|
235 |
+
with gr.Accordion(label=i18n("知识库"), open=True):
|
236 |
+
use_websearch_checkbox = gr.Checkbox(label=i18n(
|
237 |
+
"使用在线搜索"), value=False, elem_classes="switch-checkbox", elem_id="gr-websearch-cb", visible=False)
|
238 |
+
index_files = gr.Files(label=i18n(
|
239 |
+
"上传"), type="file", elem_id="upload-index-file")
|
240 |
+
two_column = gr.Checkbox(label=i18n(
|
241 |
+
"双栏pdf"), value=advance_docs["pdf"].get("two_column", False))
|
242 |
+
summarize_btn = gr.Button(i18n("总结"))
|
243 |
+
# TODO: 公式ocr
|
244 |
+
# formula_ocr = gr.Checkbox(label=i18n("识别公式"), value=advance_docs["pdf"].get("formula_ocr", False))
|
245 |
+
|
246 |
+
with gr.Tab(label=i18n("参数")):
|
247 |
+
gr.Markdown(i18n("# ⚠️ 务必谨慎更改 ⚠️"),
|
248 |
+
elem_id="advanced-warning")
|
249 |
+
with gr.Accordion(i18n("参数"), open=True):
|
250 |
+
temperature_slider = gr.Slider(
|
251 |
+
minimum=-0,
|
252 |
+
maximum=2.0,
|
253 |
+
value=1.0,
|
254 |
+
step=0.1,
|
255 |
+
interactive=True,
|
256 |
+
label="temperature",
|
257 |
+
)
|
258 |
+
top_p_slider = gr.Slider(
|
259 |
+
minimum=-0,
|
260 |
+
maximum=1.0,
|
261 |
+
value=1.0,
|
262 |
+
step=0.05,
|
263 |
+
interactive=True,
|
264 |
+
label="top-p",
|
265 |
+
)
|
266 |
+
n_choices_slider = gr.Slider(
|
267 |
+
minimum=1,
|
268 |
+
maximum=10,
|
269 |
+
value=1,
|
270 |
+
step=1,
|
271 |
+
interactive=True,
|
272 |
+
label="n choices",
|
273 |
+
)
|
274 |
+
stop_sequence_txt = gr.Textbox(
|
275 |
+
show_label=True,
|
276 |
+
placeholder=i18n("停止符,用英文逗号隔开..."),
|
277 |
+
label="stop",
|
278 |
+
value="",
|
279 |
+
lines=1,
|
280 |
+
)
|
281 |
+
max_context_length_slider = gr.Slider(
|
282 |
+
minimum=1,
|
283 |
+
maximum=32768,
|
284 |
+
value=2000,
|
285 |
+
step=1,
|
286 |
+
interactive=True,
|
287 |
+
label="max context",
|
288 |
+
)
|
289 |
+
max_generation_slider = gr.Slider(
|
290 |
+
minimum=1,
|
291 |
+
maximum=32768,
|
292 |
+
value=1000,
|
293 |
+
step=1,
|
294 |
+
interactive=True,
|
295 |
+
label="max generations",
|
296 |
+
)
|
297 |
+
presence_penalty_slider = gr.Slider(
|
298 |
+
minimum=-2.0,
|
299 |
+
maximum=2.0,
|
300 |
+
value=0.0,
|
301 |
+
step=0.01,
|
302 |
+
interactive=True,
|
303 |
+
label="presence penalty",
|
304 |
+
)
|
305 |
+
frequency_penalty_slider = gr.Slider(
|
306 |
+
minimum=-2.0,
|
307 |
+
maximum=2.0,
|
308 |
+
value=0.0,
|
309 |
+
step=0.01,
|
310 |
+
interactive=True,
|
311 |
+
label="frequency penalty",
|
312 |
+
)
|
313 |
+
logit_bias_txt = gr.Textbox(
|
314 |
+
show_label=True,
|
315 |
+
placeholder=f"word:likelihood",
|
316 |
+
label="logit bias",
|
317 |
+
value="",
|
318 |
+
lines=1,
|
319 |
+
)
|
320 |
+
user_identifier_txt = gr.Textbox(
|
321 |
+
show_label=True,
|
322 |
+
placeholder=i18n("用于定位滥用行为"),
|
323 |
+
label=i18n("用户名"),
|
324 |
+
value=user_name.value,
|
325 |
+
lines=1,
|
326 |
+
)
|
327 |
+
with gr.Tab(label=i18n("拓展")):
|
328 |
+
gr.Markdown(
|
329 |
+
"Will be here soon...\n(We hope)\n\nAnd we hope you can help us to make more extensions!")
|
330 |
+
|
331 |
+
# changeAPIURLBtn = gr.Button(i18n("🔄 切换API地址"))
|
332 |
+
|
333 |
+
with gr.Row(elem_id="popup-wrapper"):
|
334 |
+
with gr.Box(elem_id="chuanhu-popup"):
|
335 |
+
with gr.Box(elem_id="chuanhu-setting"):
|
336 |
+
with gr.Row():
|
337 |
+
gr.Markdown("## "+i18n("设置"))
|
338 |
+
gr.HTML(get_html("close_btn.html").format(
|
339 |
+
obj="box"), elem_classes="close-btn")
|
340 |
+
with gr.Tabs(elem_id="chuanhu-setting-tabs"):
|
341 |
+
with gr.Tab(label=i18n("模型")):
|
342 |
+
keyTxt = gr.Textbox(
|
343 |
show_label=True,
|
344 |
+
placeholder=f"Your API-key...",
|
345 |
+
value=hide_middle_chars(user_api_key.value),
|
346 |
+
type="password",
|
347 |
+
visible=not HIDE_MY_KEY,
|
348 |
+
label="API-Key",
|
349 |
)
|
350 |
+
if multi_api_key:
|
351 |
+
usageTxt = gr.Markdown(i18n(
|
352 |
+
"多账号模式已开启,无需输入key,可直接开始对话"), elem_id="usage-display", elem_classes="insert-block", visible=show_api_billing)
|
353 |
+
else:
|
354 |
+
usageTxt = gr.Markdown(i18n(
|
355 |
+
"**发送消息** 或 **提交key** 以显示额度"), elem_id="usage-display", elem_classes="insert-block", visible=show_api_billing)
|
356 |
+
# model_select_dropdown = gr.Dropdown(
|
357 |
+
# label=i18n("选择模型"), choices=MODELS, multiselect=False, value=MODELS[DEFAULT_MODEL], interactive=True
|
358 |
+
# )
|
359 |
+
# lora_select_dropdown = gr.Dropdown(
|
360 |
+
# label=i18n("选择LoRA模型"), choices=[], multiselect=False, interactive=True, visible=False
|
361 |
+
# )
|
362 |
+
# with gr.Row():
|
363 |
+
|
364 |
+
language_select_dropdown = gr.Dropdown(
|
365 |
+
label=i18n("选择回复语言(针对搜索&索引功能)"),
|
366 |
+
choices=REPLY_LANGUAGES,
|
367 |
+
multiselect=False,
|
368 |
+
value=REPLY_LANGUAGES[0],
|
369 |
)
|
370 |
+
|
371 |
+
with gr.Tab(label=i18n("高级")):
|
372 |
+
gr.HTML(get_html("appearance_switcher.html").format(
|
373 |
+
label=i18n("切换亮暗色主题")), elem_classes="insert-block", visible=False)
|
374 |
+
use_streaming_checkbox = gr.Checkbox(
|
375 |
+
label=i18n("实时传输回答"), value=True, visible=ENABLE_STREAMING_OPTION, elem_classes="switch-checkbox"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
376 |
)
|
377 |
+
name_chat_method = gr.Dropdown(
|
378 |
+
label=i18n("对话命名方式"),
|
379 |
+
choices=HISTORY_NAME_METHODS,
|
380 |
+
multiselect=False,
|
|
|
381 |
interactive=True,
|
382 |
+
value=HISTORY_NAME_METHODS[chat_name_method_index],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
383 |
)
|
384 |
+
single_turn_checkbox = gr.Checkbox(label=i18n(
|
385 |
+
"单轮对话"), value=False, elem_classes="switch-checkbox", elem_id="gr-single-session-cb", visible=False)
|
386 |
+
# checkUpdateBtn = gr.Button(i18n("🔄 检查更新..."), visible=check_update)
|
387 |
|
388 |
+
with gr.Tab(i18n("网络")):
|
389 |
+
gr.Markdown(
|
390 |
+
i18n("⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置"), elem_id="netsetting-warning")
|
391 |
default_btn = gr.Button(i18n("🔙 恢复默认网络设置"))
|
392 |
# 网络代理
|
393 |
proxyTxt = gr.Textbox(
|
|
|
413 |
# container=False,
|
414 |
elem_classes="view-only-textbox no-container",
|
415 |
)
|
|
|
|
|
416 |
|
417 |
+
with gr.Tab(label=i18n("关于"), elem_id="about-tab"):
|
418 |
+
gr.Markdown(
|
419 |
+
'<img alt="Chuanhu Chat logo" src="file=web_assets/icon/any-icon-512.png" style="max-width: 144px;">')
|
420 |
+
gr.Markdown("# "+i18n("川虎Chat"))
|
421 |
+
gr.HTML(get_html("footer.html").format(
|
422 |
+
versions=versions_html()), elem_id="footer")
|
423 |
+
gr.Markdown(CHUANHU_DESCRIPTION, elem_id="description")
|
424 |
+
|
425 |
+
with gr.Box(elem_id="chuanhu-training"):
|
426 |
+
with gr.Row():
|
427 |
+
gr.Markdown("## "+i18n("训练"))
|
428 |
+
gr.HTML(get_html("close_btn.html").format(
|
429 |
+
obj="box"), elem_classes="close-btn")
|
430 |
+
with gr.Tabs(elem_id="chuanhu-training-tabs"):
|
431 |
+
with gr.Tab(label="OpenAI "+i18n("微调")):
|
432 |
+
openai_train_status = gr.Markdown(label=i18n("训练状态"), value=i18n(
|
433 |
+
"查看[使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)"))
|
434 |
+
|
435 |
+
with gr.Tab(label=i18n("准备数据集")):
|
436 |
+
dataset_preview_json = gr.JSON(
|
437 |
+
label=i18n("数据集预览"))
|
438 |
+
dataset_selection = gr.Files(label=i18n("选择数据集"), file_types=[
|
439 |
+
".xlsx", ".jsonl"], file_count="single")
|
440 |
+
upload_to_openai_btn = gr.Button(
|
441 |
+
i18n("上传到OpenAI"), variant="primary", interactive=False)
|
442 |
+
|
443 |
+
with gr.Tab(label=i18n("训练")):
|
444 |
+
openai_ft_file_id = gr.Textbox(label=i18n(
|
445 |
+
"文件ID"), value="", lines=1, placeholder=i18n("上传到 OpenAI 后自动填充"))
|
446 |
+
openai_ft_suffix = gr.Textbox(label=i18n(
|
447 |
+
"模型名称后缀"), value="", lines=1, placeholder=i18n("可选,用于区分不同的模型"))
|
448 |
+
openai_train_epoch_slider = gr.Slider(label=i18n(
|
449 |
+
"训练轮数(Epochs)"), minimum=1, maximum=100, value=3, step=1, interactive=True)
|
450 |
+
openai_start_train_btn = gr.Button(
|
451 |
+
i18n("开始训练"), variant="primary", interactive=False)
|
452 |
+
|
453 |
+
with gr.Tab(label=i18n("状态")):
|
454 |
+
openai_status_refresh_btn = gr.Button(i18n("刷新状态"))
|
455 |
+
openai_cancel_all_jobs_btn = gr.Button(
|
456 |
+
i18n("取消所有任务"))
|
457 |
+
add_to_models_btn = gr.Button(
|
458 |
+
i18n("添加训练好的模型到模型列表"), interactive=False)
|
459 |
+
|
460 |
+
with gr.Box(elem_id="web-config", visible=False):
|
461 |
+
gr.HTML(get_html('web_config.html').format(
|
462 |
+
enableCheckUpdate_config=check_update,
|
463 |
+
hideHistoryWhenNotLoggedIn_config=hide_history_when_not_logged_in,
|
464 |
+
forView_i18n=i18n("仅供查看"),
|
465 |
+
deleteConfirm_i18n_pref=i18n("你真的要删除 "),
|
466 |
+
deleteConfirm_i18n_suff=i18n(" 吗?"),
|
467 |
+
usingLatest_i18n=i18n("您使用的就是最新版!"),
|
468 |
+
updatingMsg_i18n=i18n("正在尝试更新..."),
|
469 |
+
updateSuccess_i18n=i18n("更新成功,请重启本程序"),
|
470 |
+
updateFailure_i18n=i18n(
|
471 |
+
"更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)"),
|
472 |
+
regenerate_i18n=i18n("重新生成"),
|
473 |
+
deleteRound_i18n=i18n("删除这轮问答"),
|
474 |
+
renameChat_i18n=i18n("重命名该对话"),
|
475 |
+
validFileName_i18n=i18n("请输入有效的文件名,不要包含以下特殊字符:"),
|
476 |
+
))
|
477 |
+
with gr.Box(elem_id="fake-gradio-components", visible=False):
|
478 |
+
updateChuanhuBtn = gr.Button(
|
479 |
+
visible=False, elem_classes="invisible-btn", elem_id="update-chuanhu-btn")
|
480 |
+
changeSingleSessionBtn = gr.Button(
|
481 |
+
visible=False, elem_classes="invisible-btn", elem_id="change-single-session-btn")
|
482 |
+
changeOnlineSearchBtn = gr.Button(
|
483 |
+
visible=False, elem_classes="invisible-btn", elem_id="change-online-search-btn")
|
484 |
+
historySelectBtn = gr.Button(
|
485 |
+
visible=False, elem_classes="invisible-btn", elem_id="history-select-btn") # Not used
|
486 |
|
487 |
# https://github.com/gradio-app/gradio/pull/3296
|
488 |
+
|
489 |
def create_greeting(request: gr.Request):
|
490 |
+
if hasattr(request, "username") and request.username: # is not None or is not ""
|
491 |
logging.info(f"Get User Name: {request.username}")
|
492 |
+
user_info, user_name = gr.Markdown.update(
|
493 |
+
value=f"User: {request.username}"), request.username
|
494 |
else:
|
495 |
+
user_info, user_name = gr.Markdown.update(
|
496 |
+
value=f"", visible=False), ""
|
497 |
+
current_model = get_model(
|
498 |
+
model_name=MODELS[DEFAULT_MODEL], access_key=my_api_key)[0]
|
499 |
current_model.set_user_identifier(user_name)
|
500 |
+
if not hide_history_when_not_logged_in or user_name:
|
501 |
+
filename, system_prompt, chatbot = current_model.auto_load()
|
502 |
+
else:
|
503 |
+
system_prompt = gr.update()
|
504 |
+
filename = gr.update()
|
505 |
+
chatbot = gr.Chatbot.update(label=MODELS[DEFAULT_MODEL])
|
506 |
+
return user_info, user_name, current_model, toggle_like_btn_visibility(DEFAULT_MODEL), filename, system_prompt, chatbot, init_history_list(user_name)
|
507 |
+
demo.load(create_greeting, inputs=None, outputs=[
|
508 |
+
user_info, user_name, current_model, like_dislike_area, saveFileName, systemPromptTxt, chatbot, historySelectList], api_name="load")
|
509 |
chatgpt_predict_args = dict(
|
510 |
fn=predict,
|
511 |
inputs=[
|
|
|
537 |
)
|
538 |
|
539 |
transfer_input_args = dict(
|
540 |
+
fn=transfer_input, inputs=[user_input], outputs=[
|
541 |
+
user_question, user_input, submitBtn, cancelBtn], show_progress=True
|
542 |
)
|
543 |
|
544 |
get_usage_args = dict(
|
545 |
+
fn=billing_info, inputs=[current_model], outputs=[
|
546 |
+
usageTxt], show_progress=False
|
547 |
)
|
548 |
|
549 |
load_history_from_file_args = dict(
|
550 |
fn=load_chat_history,
|
551 |
+
inputs=[current_model, historySelectList, user_name],
|
552 |
outputs=[saveFileName, systemPromptTxt, chatbot]
|
553 |
)
|
554 |
|
555 |
refresh_history_args = dict(
|
556 |
+
fn=get_history_list, inputs=[user_name], outputs=[historySelectList]
|
557 |
)
|
558 |
|
559 |
+
auto_name_chat_history_args = dict(
|
560 |
+
fn=auto_name_chat_history,
|
561 |
+
inputs=[current_model, name_chat_method, user_question, chatbot, user_name, single_turn_checkbox],
|
562 |
+
outputs=[historySelectList],
|
563 |
+
show_progress=False,
|
564 |
+
)
|
565 |
|
566 |
# Chatbot
|
567 |
cancelBtn.click(interrupt, [current_model], [])
|
568 |
|
569 |
+
user_input.submit(**transfer_input_args).then(**
|
570 |
+
chatgpt_predict_args).then(**end_outputing_args).then(**auto_name_chat_history_args)
|
571 |
user_input.submit(**get_usage_args)
|
572 |
|
573 |
+
# user_input.submit(auto_name_chat_history, [current_model, user_question, chatbot, user_name], [historySelectList], show_progress=False)
|
574 |
+
|
575 |
+
submitBtn.click(**transfer_input_args).then(**chatgpt_predict_args,
|
576 |
+
api_name="predict").then(**end_outputing_args).then(**auto_name_chat_history_args)
|
577 |
submitBtn.click(**get_usage_args)
|
578 |
|
579 |
+
# submitBtn.click(auto_name_chat_history, [current_model, user_question, chatbot, user_name], [historySelectList], show_progress=False)
|
580 |
+
|
581 |
+
index_files.upload(handle_file_upload, [current_model, index_files, chatbot, language_select_dropdown], [
|
582 |
+
index_files, chatbot, status_display])
|
583 |
+
summarize_btn.click(handle_summarize_index, [
|
584 |
+
current_model, index_files, chatbot, language_select_dropdown], [chatbot, status_display])
|
585 |
|
586 |
emptyBtn.click(
|
587 |
reset,
|
588 |
+
inputs=[current_model, retain_system_prompt_checkbox],
|
589 |
+
outputs=[chatbot, status_display, historySelectList, systemPromptTxt],
|
590 |
show_progress=True,
|
591 |
+
_js='(a,b)=>{return clearChatbot(a,b);}',
|
592 |
)
|
593 |
|
594 |
retryBtn.click(**start_outputing_args).then(
|
|
|
636 |
two_column.change(update_doc_config, [two_column], None)
|
637 |
|
638 |
# LLM Models
|
639 |
+
keyTxt.change(set_key, [current_model, keyTxt], [
|
640 |
+
user_api_key, status_display], api_name="set_key").then(**get_usage_args)
|
641 |
keyTxt.submit(**get_usage_args)
|
642 |
+
single_turn_checkbox.change(
|
643 |
+
set_single_turn, [current_model, single_turn_checkbox], None)
|
644 |
+
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], [
|
645 |
+
current_model, status_display, chatbot, lora_select_dropdown, user_api_key, keyTxt], show_progress=True, api_name="get_model")
|
646 |
+
model_select_dropdown.change(toggle_like_btn_visibility, [model_select_dropdown], [
|
647 |
+
like_dislike_area], show_progress=False)
|
648 |
+
lora_select_dropdown.change(get_model, [model_select_dropdown, lora_select_dropdown, user_api_key, temperature_slider,
|
649 |
+
top_p_slider, systemPromptTxt, user_name, current_model], [current_model, status_display, chatbot], show_progress=True)
|
650 |
|
651 |
# Template
|
652 |
+
systemPromptTxt.change(set_system_prompt, [
|
653 |
+
current_model, systemPromptTxt], None)
|
654 |
+
templateRefreshBtn.click(get_template_dropdown, None, [
|
655 |
+
templateFileSelectDropdown])
|
656 |
+
templateFileSelectDropdown.input(
|
657 |
load_template,
|
658 |
[templateFileSelectDropdown],
|
659 |
[promptTemplates, templateSelectDropdown],
|
|
|
667 |
)
|
668 |
|
669 |
# S&L
|
670 |
+
renameHistoryBtn.click(
|
671 |
+
rename_chat_history,
|
672 |
[current_model, saveFileName, chatbot, user_name],
|
673 |
+
[historySelectList],
|
674 |
show_progress=True,
|
675 |
+
_js='(a,b,c,d)=>{return saveChatHistory(a,b,c,d);}'
|
676 |
)
|
|
|
677 |
exportMarkdownBtn.click(
|
678 |
export_markdown,
|
679 |
[current_model, saveFileName, chatbot, user_name],
|
680 |
+
[],
|
681 |
show_progress=True,
|
682 |
)
|
683 |
historyRefreshBtn.click(**refresh_history_args)
|
684 |
+
historyDeleteBtn.click(delete_chat_history, [current_model, historySelectList, user_name], [status_display, historySelectList, chatbot], _js='(a,b,c)=>{return showConfirmationDialog(a, b, c);}').then(
|
685 |
+
reset,
|
686 |
+
inputs=[current_model, retain_system_prompt_checkbox],
|
687 |
+
outputs=[chatbot, status_display, historySelectList, systemPromptTxt],
|
688 |
+
show_progress=True,
|
689 |
+
_js='(a,b)=>{return clearChatbot(a,b);}',
|
690 |
+
)
|
691 |
+
historySelectList.input(**load_history_from_file_args)
|
692 |
+
uploadFileBtn.upload(upload_chat_history, [current_model, uploadFileBtn, user_name], [
|
693 |
+
saveFileName, systemPromptTxt, chatbot]).then(**refresh_history_args)
|
694 |
+
historyDownloadBtn.click(None, [
|
695 |
+
user_name, historySelectList], None, _js='(a,b)=>{return downloadHistory(a,b,".json");}')
|
696 |
+
historyMarkdownDownloadBtn.click(None, [
|
697 |
+
user_name, historySelectList], None, _js='(a,b)=>{return downloadHistory(a,b,".md");}')
|
698 |
+
historySearchTextbox.input(
|
699 |
+
filter_history,
|
700 |
+
[user_name, historySearchTextbox],
|
701 |
+
[historySelectList]
|
702 |
+
)
|
703 |
|
704 |
# Train
|
705 |
+
dataset_selection.upload(handle_dataset_selection, dataset_selection, [
|
706 |
+
dataset_preview_json, upload_to_openai_btn, openai_train_status])
|
707 |
+
dataset_selection.clear(handle_dataset_clear, [], [
|
708 |
+
dataset_preview_json, upload_to_openai_btn])
|
709 |
+
upload_to_openai_btn.click(upload_to_openai, [dataset_selection], [
|
710 |
+
openai_ft_file_id, openai_train_status], show_progress=True)
|
711 |
+
|
712 |
+
openai_ft_file_id.change(lambda x: gr.update(interactive=True) if len(
|
713 |
+
x) > 0 else gr.update(interactive=False), [openai_ft_file_id], [openai_start_train_btn])
|
714 |
+
openai_start_train_btn.click(start_training, [
|
715 |
+
openai_ft_file_id, openai_ft_suffix, openai_train_epoch_slider], [openai_train_status])
|
716 |
+
|
717 |
+
openai_status_refresh_btn.click(get_training_status, [], [
|
718 |
+
openai_train_status, add_to_models_btn])
|
719 |
+
add_to_models_btn.click(add_to_models, [], [
|
720 |
+
model_select_dropdown, openai_train_status], show_progress=True)
|
721 |
+
openai_cancel_all_jobs_btn.click(
|
722 |
+
cancel_all_jobs, [], [openai_train_status], show_progress=True)
|
723 |
|
724 |
# Advanced
|
725 |
+
max_context_length_slider.change(
|
726 |
+
set_token_upper_limit, [current_model, max_context_length_slider], None)
|
727 |
+
temperature_slider.change(
|
728 |
+
set_temperature, [current_model, temperature_slider], None)
|
729 |
top_p_slider.change(set_top_p, [current_model, top_p_slider], None)
|
730 |
+
n_choices_slider.change(
|
731 |
+
set_n_choices, [current_model, n_choices_slider], None)
|
732 |
+
stop_sequence_txt.change(
|
733 |
+
set_stop_sequence, [current_model, stop_sequence_txt], None)
|
734 |
+
max_generation_slider.change(
|
735 |
+
set_max_tokens, [current_model, max_generation_slider], None)
|
736 |
+
presence_penalty_slider.change(
|
737 |
+
set_presence_penalty, [current_model, presence_penalty_slider], None)
|
738 |
+
frequency_penalty_slider.change(
|
739 |
+
set_frequency_penalty, [current_model, frequency_penalty_slider], None)
|
740 |
+
logit_bias_txt.change(
|
741 |
+
set_logit_bias, [current_model, logit_bias_txt], None)
|
742 |
+
user_identifier_txt.change(set_user_identifier, [
|
743 |
+
current_model, user_identifier_txt], None)
|
744 |
|
745 |
default_btn.click(
|
746 |
reset_default, [], [apihostTxt, proxyTxt, status_display], show_progress=True
|
|
|
757 |
# [status_display],
|
758 |
# show_progress=True,
|
759 |
# )
|
760 |
+
# checkUpdateBtn.click(fn=None, _js='manualCheckUpdate')
|
761 |
|
762 |
# Invisible elements
|
763 |
updateChuanhuBtn.click(
|
|
|
766 |
[status_display],
|
767 |
show_progress=True,
|
768 |
)
|
769 |
+
changeSingleSessionBtn.click(
|
770 |
+
fn=lambda value: gr.Checkbox.update(value=value),
|
771 |
+
inputs=[single_turn_checkbox],
|
772 |
+
outputs=[single_turn_checkbox],
|
773 |
+
_js='(a)=>{return bgChangeSingleSession(a);}'
|
774 |
+
)
|
775 |
+
changeOnlineSearchBtn.click(
|
776 |
+
fn=lambda value: gr.Checkbox.update(value=value),
|
777 |
+
inputs=[use_websearch_checkbox],
|
778 |
+
outputs=[use_websearch_checkbox],
|
779 |
+
_js='(a)=>{return bgChangeOnlineSearch(a);}'
|
780 |
+
)
|
781 |
+
historySelectBtn.click( # This is an experimental feature... Not actually used.
|
782 |
+
fn=load_chat_history,
|
783 |
+
inputs=[current_model, historySelectList],
|
784 |
+
outputs=[saveFileName, systemPromptTxt, chatbot],
|
785 |
+
_js='(a,b)=>{return bgSelectHistory(a,b);}'
|
786 |
+
)
|
787 |
+
|
788 |
|
789 |
logging.info(
|
790 |
colorama.Back.GREEN
|
|
|
797 |
if __name__ == "__main__":
|
798 |
reload_javascript()
|
799 |
demo.queue(concurrency_count=CONCURRENT_COUNT).launch(
|
800 |
+
allowed_paths=["history", "web_assets"],
|
801 |
+
server_name=server_name,
|
802 |
+
server_port=server_port,
|
803 |
+
share=share,
|
804 |
+
auth=auth_from_conf if authflag else None,
|
805 |
favicon_path="./web_assets/favicon.ico",
|
806 |
+
inbrowser=not dockerflag, # 禁止在docker下开启inbrowser
|
807 |
)
|
config_example.json
CHANGED
@@ -11,6 +11,10 @@
|
|
11 |
"midjourney_proxy_api_secret": "", // 你的 MidJourney Proxy API Secret,用于鉴权访问 api,可选
|
12 |
"midjourney_discord_proxy_url": "", // 你的 MidJourney Discord Proxy URL,用于对生成对图进行反代,可选
|
13 |
"midjourney_temp_folder": "./tmp", // 你的 MidJourney 临时文件夹,用于存放生成的图片,填空则关闭自动下载切图(直接显示MJ的四宫格图)
|
|
|
|
|
|
|
|
|
14 |
|
15 |
|
16 |
//== Azure ==
|
@@ -23,14 +27,15 @@
|
|
23 |
"azure_embedding_model_name": "text-embedding-ada-002", // 你的 Azure OpenAI Embedding 模型名称
|
24 |
|
25 |
//== 基础配置 ==
|
26 |
-
"language": "auto", // 界面语言,可选"auto", "
|
27 |
"users": [], // 用户列表,[[用户名1, 密码1], [用户名2, 密码2], ...]
|
28 |
"local_embedding": false, //是否在本地编制索引
|
29 |
"hide_history_when_not_logged_in": false, //未登录情况下是否不展示对话历史
|
30 |
"check_update": true, //是否启用检查更新
|
31 |
"default_model": "gpt-3.5-turbo", // 默认模型
|
32 |
-
"
|
33 |
-
"
|
|
|
34 |
|
35 |
//== API 用量 ==
|
36 |
"show_api_billing": false, //是否显示OpenAI API用量(启用需要填写sensitive_id)
|
@@ -57,11 +62,13 @@
|
|
57 |
//== 高级配置 ==
|
58 |
// 是否多个API Key轮换使用
|
59 |
"multi_api_key": false,
|
60 |
-
"
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
|
|
|
|
65 |
// 自定义OpenAI API Base
|
66 |
// "openai_api_base": "https://api.openai.com",
|
67 |
// 自定义使用代理(请替换代理URL)
|
|
|
11 |
"midjourney_proxy_api_secret": "", // 你的 MidJourney Proxy API Secret,用于鉴权访问 api,可选
|
12 |
"midjourney_discord_proxy_url": "", // 你的 MidJourney Discord Proxy URL,用于对生成对图进行反代,可选
|
13 |
"midjourney_temp_folder": "./tmp", // 你的 MidJourney 临时文件夹,用于存放生成的图片,填空则关闭自动下载切图(直接显示MJ的四宫格图)
|
14 |
+
"spark_appid": "", // 你的 讯飞星火大模型 API AppID,用于讯飞星火大模型对话模型
|
15 |
+
"spark_api_key": "", // 你的 讯飞星火大模型 API Key,用于讯飞星火大模型对话模型
|
16 |
+
"spark_api_secret": "", // 你的 讯飞星火大模型 API Secret,用于讯飞星火大模型对话模型
|
17 |
+
"claude_api_secret":"",// 你的 Claude API Secret,用于 Claude 对话模型
|
18 |
|
19 |
|
20 |
//== Azure ==
|
|
|
27 |
"azure_embedding_model_name": "text-embedding-ada-002", // 你的 Azure OpenAI Embedding 模型名称
|
28 |
|
29 |
//== 基础配置 ==
|
30 |
+
"language": "auto", // 界面语言,可选"auto", "zh_CN", "en_US", "ja_JP", "ko_KR", "sv_SE", "ru_RU", "vi_VN"
|
31 |
"users": [], // 用户列表,[[用户名1, 密码1], [用户名2, 密码2], ...]
|
32 |
"local_embedding": false, //是否在本地编制索引
|
33 |
"hide_history_when_not_logged_in": false, //未登录情况下是否不展示对话历史
|
34 |
"check_update": true, //是否启用检查更新
|
35 |
"default_model": "gpt-3.5-turbo", // 默认模型
|
36 |
+
"chat_name_method_index": 2, // 选择对话名称的方法。0: 使用日期时间命名;1: 使用第一条提问命名,2: 使用模型自动总结
|
37 |
+
"bot_avatar": "default", // 机器人头像,可填写本地或网络图片链接,或者"none"(不显示头像)
|
38 |
+
"user_avatar": "default", // 用户头像,可填写本地或网络图片链接,或者"none"(不显示头像)
|
39 |
|
40 |
//== API 用量 ==
|
41 |
"show_api_billing": false, //是否显示OpenAI API用量(启用需要填写sensitive_id)
|
|
|
62 |
//== 高级配置 ==
|
63 |
// 是否多个API Key轮换使用
|
64 |
"multi_api_key": false,
|
65 |
+
// "available_models": ["GPT3.5 Turbo", "GPT4 Turbo", "GPT4 Vision"], // 可用的模型列表,将覆盖默认的可用模型列表
|
66 |
+
// "extra_models": ["模型名称3", "模型名称4", ...], // 额外的模型,将添加到可用的模型列表之后
|
67 |
+
// "api_key_list": [
|
68 |
+
// "sk-xxxxxxxxxxxxxxxxxxxxxxxx1",
|
69 |
+
// "sk-xxxxxxxxxxxxxxxxxxxxxxxx2",
|
70 |
+
// "sk-xxxxxxxxxxxxxxxxxxxxxxxx3"
|
71 |
+
// ],
|
72 |
// 自定义OpenAI API Base
|
73 |
// "openai_api_base": "https://api.openai.com",
|
74 |
// 自定义使用代理(请替换代理URL)
|
locale/en_US.json
CHANGED
@@ -1,87 +1,141 @@
|
|
1 |
{
|
2 |
-
"
|
3 |
-
"
|
4 |
-
"🧹 新的对话": "🧹 New Dialogue",
|
5 |
-
"🔄 重新生成": "🔄 Regeneration",
|
6 |
-
"🗑️ 删除最旧对话": "🗑️ Delete oldest dialog",
|
7 |
-
"🗑️ 删除最新对话": "🗑️ Delete latest dialog",
|
8 |
-
"模型": "Model",
|
9 |
-
"多账号模式已开启,无需输入key,可直接开始对话": "Multi-account mode is enabled, no need to enter key, you can start the dialogue directly",
|
10 |
"**发送消息** 或 **提交key** 以显示额度": "**Send message** or **Submit key** to display credit",
|
11 |
-
"
|
12 |
-
"
|
13 |
-
"
|
14 |
-
"
|
15 |
-
"
|
16 |
-
"
|
17 |
-
"
|
18 |
-
"
|
19 |
-
"
|
20 |
-
"
|
21 |
-
"
|
22 |
-
"
|
23 |
-
"
|
|
|
|
|
|
|
|
|
|
|
24 |
"从Prompt模板中加载": "Load from Prompt Template",
|
25 |
-
"保存/加载": "Save/Load",
|
26 |
-
"保存/加载对话历史记录": "Save/Load Dialog History",
|
27 |
"从列表中加载对话": "Load dialog from list",
|
28 |
-
"设置文件名: 默认为.json,可选为.md": "Set file name: default is .json, optional is .md",
|
29 |
-
"设置保存文件名": "Set save file name",
|
30 |
-
"对话历史记录": "Dialog History",
|
31 |
-
"💾 保存对话": "💾 Save Dialog",
|
32 |
-
"📝 导出为Markdown": "📝 Export as Markdown",
|
33 |
-
"默认保存于history文件夹": "Default save in history folder",
|
34 |
-
"高级": "Advanced",
|
35 |
-
"# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ Caution: Changes require care. ⚠️",
|
36 |
-
"参数": "Parameters",
|
37 |
-
"停止符,用英文逗号隔开...": "Type in stop token here, separated by comma...",
|
38 |
-
"用于定位滥用行为": "Used to locate abuse",
|
39 |
-
"用户名": "Username",
|
40 |
-
"在这里输入API-Host...": "Type in API-Host here...",
|
41 |
-
"🔄 切换API地址": "🔄 Switch API Address",
|
42 |
-
"未设置代理...": "No proxy...",
|
43 |
"代理地址": "Proxy address",
|
44 |
-
"
|
45 |
-
"
|
46 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
"取消": "Cancel",
|
48 |
-
"
|
49 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
"好": "OK",
|
51 |
-
"
|
52 |
-
"
|
|
|
|
|
|
|
|
|
|
|
53 |
"川虎Chat 🚀": "Chuanhu Chat 🚀",
|
|
|
|
|
54 |
"开始实时传输回答……": "Start streaming output...",
|
55 |
-
"
|
56 |
-
"
|
57 |
-
"
|
58 |
-
"
|
59 |
-
"
|
60 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
"本月使用金额": "Monthly usage",
|
62 |
-
"
|
63 |
-
"
|
64 |
-
"
|
|
|
|
|
65 |
"模型设置为了:": "Model is set to: ",
|
66 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
"获取对话时发生错误,请查看后台日志": "Error occurred when getting dialogue, check the background log",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
"请检查网络连接,或者API-Key是否有效。": "Check the network connection or whether the API-Key is valid.",
|
69 |
-
"连接超时,无法获取对话。": "Connection timed out, unable to get dialogue.",
|
70 |
-
"读取超时,无法获取对话。": "Read timed out, unable to get dialogue.",
|
71 |
-
"代理错误,无法获取对话。": "Proxy error, unable to get dialogue.",
|
72 |
-
"SSL错误,无法获取对话。": "SSL error, unable to get dialogue.",
|
73 |
-
"API key为空,请检查是否输入正确。": "API key is empty, check whether it is entered correctly.",
|
74 |
"请输入对话内容。": "Enter the content of the conversation.",
|
|
|
|
|
75 |
"账单信息不适用": "Billing information is not applicable",
|
76 |
-
"
|
77 |
-
"
|
78 |
-
"
|
79 |
-
"
|
80 |
-
"
|
81 |
-
"
|
82 |
-
"
|
83 |
-
"
|
84 |
-
"
|
85 |
-
"
|
86 |
-
"
|
87 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
{
|
2 |
+
" 吗?": " ?",
|
3 |
+
"# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ Caution: Changes require care. ⚠️",
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
"**发送消息** 或 **提交key** 以显示额度": "**Send message** or **Submit key** to display credit",
|
5 |
+
"**本月使用金额** ": "**Monthly usage** ",
|
6 |
+
"**获取API使用情况失败**": "**Failed to get API usage**",
|
7 |
+
"**获取API使用情况失败**,sensitive_id错误或已过期": "**Failed to get API usage**, wrong or expired sensitive_id",
|
8 |
+
"**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**Failed to get API usage**, correct sensitive_id needed in `config.json`",
|
9 |
+
"API key为空,请检查是否输入正确。": "API key is empty, check whether it is entered correctly.",
|
10 |
+
"API密钥更改为了": "The API key is changed to",
|
11 |
+
"JSON解析错误,收到的内容: ": "JSON parsing error, received content: ",
|
12 |
+
"SSL错误,无法获取对话。": "SSL error, unable to get dialogue.",
|
13 |
+
"Token 计数: ": "Token Count: ",
|
14 |
+
"☹️发生了错误:": "☹️Error: ",
|
15 |
+
"⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "⚠️ To ensure the security of API-Key, please modify the network settings in the configuration file `config.json`.",
|
16 |
+
"。你仍然可以使用聊天功能。": ". You can still use the chat function.",
|
17 |
+
"上传": "Upload",
|
18 |
+
"上传了": "Uploaded",
|
19 |
+
"上传到 OpenAI 后自动填充": "Automatically filled after uploading to OpenAI",
|
20 |
+
"上传到OpenAI": "Upload to OpenAI",
|
21 |
+
"上传文件": "Upload files",
|
22 |
+
"仅供查看": "For viewing only",
|
23 |
"从Prompt模板中加载": "Load from Prompt Template",
|
|
|
|
|
24 |
"从列表中加载对话": "Load dialog from list",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
"代理地址": "Proxy address",
|
26 |
+
"代理错误,无法获取对话。": "Proxy error, unable to get dialogue.",
|
27 |
+
"你没有权限访问 GPT4,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)": "You do not have permission to access GPT-4, [learn more](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)",
|
28 |
+
"你没有选择任何对话历史": "You have not selected any conversation history.",
|
29 |
+
"你真的要删除 ": "Are you sure you want to delete ",
|
30 |
+
"使用在线搜索": "Use online search",
|
31 |
+
"停止符,用英文逗号隔开...": "Type in stop token here, separated by comma...",
|
32 |
+
"关于": "About",
|
33 |
+
"准备数据集": "Prepare Dataset",
|
34 |
+
"切换亮暗色主题": "Switch light/dark theme",
|
35 |
+
"删除对话历史成功": "Successfully deleted conversation history.",
|
36 |
+
"删除这轮问答": "Delete this round of Q&A",
|
37 |
+
"刷新状态": "Refresh Status",
|
38 |
+
"��余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)": "Insufficient remaining quota, [learn more](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)",
|
39 |
+
"加载Prompt模板": "Load Prompt Template",
|
40 |
+
"单轮对话": "Single-turn",
|
41 |
+
"历史记录(JSON)": "History file (JSON)",
|
42 |
+
"参数": "Parameters",
|
43 |
+
"双栏pdf": "Two-column pdf",
|
44 |
"取消": "Cancel",
|
45 |
+
"取消所有任务": "Cancel All Tasks",
|
46 |
+
"可选,用于区分不同的模型": "Optional, used to distinguish different models",
|
47 |
+
"启用的工具:": "Enabled tools: ",
|
48 |
+
"在工具箱中管理知识库文件": "Manage knowledge base files in the toolbox",
|
49 |
+
"在线搜索": "Web search",
|
50 |
+
"在这里输入": "Type in here",
|
51 |
+
"在这里输入System Prompt...": "Type in System Prompt here...",
|
52 |
+
"多账号模式已开启,无需输入key,可直接开始对话": "Multi-account mode is enabled, no need to enter key, you can start the dialogue directly",
|
53 |
"好": "OK",
|
54 |
+
"实时传输回答": "Stream output",
|
55 |
+
"对话": "Dialogue",
|
56 |
+
"对话历史": "Conversation history",
|
57 |
+
"对话历史记录": "Dialog History",
|
58 |
+
"对话命名方式": "History naming method",
|
59 |
+
"导出为 Markdown": "Export as Markdown",
|
60 |
+
"川虎Chat": "Chuanhu Chat",
|
61 |
"川虎Chat 🚀": "Chuanhu Chat 🚀",
|
62 |
+
"工具箱": "Toolbox",
|
63 |
+
"已经被删除啦": "It has been deleted.",
|
64 |
"开始实时传输回答……": "Start streaming output...",
|
65 |
+
"开始训练": "Start Training",
|
66 |
+
"微调": "Fine-tuning",
|
67 |
+
"总结": "Summarize",
|
68 |
+
"总结完成": "Summary completed.",
|
69 |
+
"您使用的就是最新版!": "You are using the latest version!",
|
70 |
+
"您的IP区域:": "Your IP region: ",
|
71 |
+
"您的IP区域:未知。": "Your IP region: Unknown.",
|
72 |
+
"拓展": "Extensions",
|
73 |
+
"搜索(支持正则)...": "Search (supports regex)...",
|
74 |
+
"数据集预览": "Dataset Preview",
|
75 |
+
"文件ID": "File ID",
|
76 |
+
"新对话 ": "New Chat ",
|
77 |
+
"新建对话保留Prompt": "Retain Prompt For New Chat",
|
78 |
+
"暂时未知": "Unknown",
|
79 |
+
"更新": "Update",
|
80 |
+
"更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "Update failed, please try [manually updating](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)",
|
81 |
+
"更新成功,请重启本程序": "Updated successfully, please restart this program",
|
82 |
+
"未命名对话历史记录": "Unnamed Dialog History",
|
83 |
+
"未设置代理...": "No proxy...",
|
84 |
"本月使用金额": "Monthly usage",
|
85 |
+
"查看[使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)": "View the [usage guide](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35) for more details",
|
86 |
+
"根据日期时间": "By date and time",
|
87 |
+
"模型": "Model",
|
88 |
+
"模型名称后缀": "Model Name Suffix",
|
89 |
+
"模型自动总结(消耗tokens)": "Auto summary by LLM (Consume tokens)",
|
90 |
"模型设置为了:": "Model is set to: ",
|
91 |
+
"正在尝试更新...": "Trying to update...",
|
92 |
+
"添加训练好的模型到模型列表": "Add trained model to the model list",
|
93 |
+
"状态": "Status",
|
94 |
+
"生成内容总结中……": "Generating content summary...",
|
95 |
+
"用于定位滥用行为": "Used to locate abuse",
|
96 |
+
"用户名": "Username",
|
97 |
+
"由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) 下载最新版脚本": "Developed by Bilibili [土川虎虎虎](https://space.bilibili.com/29125536), [明昭MZhao](https://space.bilibili.com/24807452) and [Keldos](https://github.com/Keldos-Li)\n\nDownload latest code from [GitHub](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
|
98 |
+
"知识库": "Knowledge base",
|
99 |
+
"知识库文件": "Knowledge base files",
|
100 |
+
"第一条提问": "By first question",
|
101 |
+
"索引构建完成": "Indexing complete.",
|
102 |
+
"网络": "Network",
|
103 |
+
"获取API使用情况失败:": "Failed to get API usage:",
|
104 |
+
"获取IP地理位置失败。原因:": "Failed to get IP location. Reason: ",
|
105 |
"获取对话时发生错误,请查看后台日志": "Error occurred when getting dialogue, check the background log",
|
106 |
+
"训练": "Training",
|
107 |
+
"训练状态": "Training Status",
|
108 |
+
"训练轮数(Epochs)": "Training Epochs",
|
109 |
+
"设置": "Settings",
|
110 |
+
"设置保存文件名": "Set save file name",
|
111 |
+
"设置文件名: 默认为.json,可选为.md": "Set file name: default is .json, optional is .md",
|
112 |
+
"识别公式": "formula OCR",
|
113 |
+
"详情": "Details",
|
114 |
+
"请查看 config_example.json,配置 Azure OpenAI": "Please review config_example.json to configure Azure OpenAI",
|
115 |
"请检查网络连接,或者API-Key是否有效。": "Check the network connection or whether the API-Key is valid.",
|
|
|
|
|
|
|
|
|
|
|
116 |
"请输入对话内容。": "Enter the content of the conversation.",
|
117 |
+
"请输入有效的文件名,不要包含以下特殊字符:": "Please enter a valid file name, do not include the following special characters: ",
|
118 |
+
"读取超时,无法获取对话。": "Read timed out, unable to get dialogue.",
|
119 |
"账单信息不适用": "Billing information is not applicable",
|
120 |
+
"连接超时,无法获取对话。": "Connection timed out, unable to get dialogue.",
|
121 |
+
"选择LoRA模型": "Select LoRA Model",
|
122 |
+
"选择Prompt模板集合文件": "Select Prompt Template Collection File",
|
123 |
+
"选择回复语言(针对搜索&索引功能)": "Select reply language (for search & index)",
|
124 |
+
"选择数据集": "Select Dataset",
|
125 |
+
"选择模型": "Select Model",
|
126 |
+
"重命名该对话": "Rename this chat",
|
127 |
+
"重新生成": "Regenerate",
|
128 |
+
"高级": "Advanced",
|
129 |
+
",本次对话累计消耗了 ": ", total cost: ",
|
130 |
+
"💾 保存对话": "💾 Save Dialog",
|
131 |
+
"📝 导出为 Markdown": "📝 Export as Markdown",
|
132 |
+
"🔄 切换API地址": "🔄 Switch API Address",
|
133 |
+
"🔄 刷新": "🔄 Refresh",
|
134 |
+
"🔄 检查更新...": "🔄 Check for Update...",
|
135 |
+
"🔄 设置代理地址": "🔄 Set Proxy Address",
|
136 |
+
"🔄 重新生成": "🔄 Regeneration",
|
137 |
+
"🔙 恢复默认网络设置": "🔙 Reset Network Settings",
|
138 |
+
"🗑️ 删除最新对话": "🗑️ Delete latest dialog",
|
139 |
+
"🗑️ 删除最旧对话": "🗑️ Delete oldest dialog",
|
140 |
+
"🧹 新的对话": "🧹 New Dialogue"
|
141 |
+
}
|
locale/extract_locale.py
CHANGED
@@ -1,26 +1,138 @@
|
|
1 |
-
import os
|
2 |
-
import
|
3 |
-
import
|
4 |
|
5 |
-
|
6 |
-
pattern = r'i18n\((\"{3}.*?\"{3}|\".*?\")\)'
|
7 |
|
8 |
-
|
9 |
-
|
10 |
-
|
|
|
11 |
|
12 |
-
# Load the .py files in the modules folder
|
13 |
-
for filename in os.listdir("modules"):
|
14 |
-
if filename.endswith(".py"):
|
15 |
-
with open(os.path.join("modules", filename), "r", encoding="utf-8") as f:
|
16 |
-
contents += f.read()
|
17 |
|
18 |
-
|
19 |
-
|
20 |
|
21 |
-
#
|
22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
-
|
25 |
-
|
26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os, json, re, sys
|
2 |
+
import aiohttp, asyncio
|
3 |
+
import commentjson
|
4 |
|
5 |
+
asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy())
|
|
|
6 |
|
7 |
+
with open("config.json", "r", encoding="utf-8") as f:
|
8 |
+
config = commentjson.load(f)
|
9 |
+
api_key = config["openai_api_key"]
|
10 |
+
url = config["openai_api_base"] + "/v1/chat/completions" if "openai_api_base" in config else "https://api.openai.com/v1/chat/completions"
|
11 |
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
+
def get_current_strings():
|
14 |
+
pattern = r'i18n\s*\(\s*["\']([^"\']*(?:\)[^"\']*)?)["\']\s*\)'
|
15 |
|
16 |
+
# Load the .py files
|
17 |
+
contents = ""
|
18 |
+
for dirpath, dirnames, filenames in os.walk("."):
|
19 |
+
for filename in filenames:
|
20 |
+
if filename.endswith(".py"):
|
21 |
+
filepath = os.path.join(dirpath, filename)
|
22 |
+
with open(filepath, 'r', encoding='utf-8') as f:
|
23 |
+
contents += f.read()
|
24 |
+
# Matching with regular expressions
|
25 |
+
matches = re.findall(pattern, contents, re.DOTALL)
|
26 |
+
data = {match.strip('()"'): '' for match in matches}
|
27 |
+
fixed_data = {} # fix some keys
|
28 |
+
for key, value in data.items():
|
29 |
+
if "](" in key and key.count("(") != key.count(")"):
|
30 |
+
fixed_data[key+")"] = value
|
31 |
+
else:
|
32 |
+
fixed_data[key] = value
|
33 |
|
34 |
+
return fixed_data
|
35 |
+
|
36 |
+
|
37 |
+
def get_locale_strings(filename):
|
38 |
+
try:
|
39 |
+
with open(filename, "r", encoding="utf-8") as f:
|
40 |
+
locale_strs = json.load(f)
|
41 |
+
except FileNotFoundError:
|
42 |
+
locale_strs = {}
|
43 |
+
return locale_strs
|
44 |
+
|
45 |
+
|
46 |
+
def sort_strings(existing_translations):
|
47 |
+
# Sort the merged data
|
48 |
+
sorted_translations = {}
|
49 |
+
# Add entries with (NOT USED) in their values
|
50 |
+
for key, value in sorted(existing_translations.items(), key=lambda x: x[0]):
|
51 |
+
if "(🔴NOT USED)" in value:
|
52 |
+
sorted_translations[key] = value
|
53 |
+
# Add entries with empty values
|
54 |
+
for key, value in sorted(existing_translations.items(), key=lambda x: x[0]):
|
55 |
+
if value == "":
|
56 |
+
sorted_translations[key] = value
|
57 |
+
# Add the rest of the entries
|
58 |
+
for key, value in sorted(existing_translations.items(), key=lambda x: x[0]):
|
59 |
+
if value != "" and "(NOT USED)" not in value:
|
60 |
+
sorted_translations[key] = value
|
61 |
+
|
62 |
+
return sorted_translations
|
63 |
+
|
64 |
+
|
65 |
+
async def auto_translate(str, language):
|
66 |
+
headers = {
|
67 |
+
"Content-Type": "application/json",
|
68 |
+
"Authorization": f"Bearer {api_key}",
|
69 |
+
"temperature": f"{0}",
|
70 |
+
}
|
71 |
+
payload = {
|
72 |
+
"model": "gpt-3.5-turbo",
|
73 |
+
"messages": [
|
74 |
+
{
|
75 |
+
"role": "system",
|
76 |
+
"content": f"You are a translation program;\nYour job is to translate user input into {language};\nThe content you are translating is a string in the App;\nDo not explain emoji;\nIf input is only a emoji, please simply return origin emoji;\nPlease ensure that the translation results are concise and easy to understand."
|
77 |
+
},
|
78 |
+
{"role": "user", "content": f"{str}"}
|
79 |
+
],
|
80 |
+
}
|
81 |
+
|
82 |
+
async with aiohttp.ClientSession() as session:
|
83 |
+
async with session.post(url, headers=headers, json=payload) as response:
|
84 |
+
data = await response.json()
|
85 |
+
return data["choices"][0]["message"]["content"]
|
86 |
+
|
87 |
+
|
88 |
+
async def main(auto=False):
|
89 |
+
current_strs = get_current_strings()
|
90 |
+
locale_files = []
|
91 |
+
# 遍历locale目录下的所有json文件
|
92 |
+
for dirpath, dirnames, filenames in os.walk("locale"):
|
93 |
+
for filename in filenames:
|
94 |
+
if filename.endswith(".json"):
|
95 |
+
locale_files.append(os.path.join(dirpath, filename))
|
96 |
+
|
97 |
+
|
98 |
+
for locale_filename in locale_files:
|
99 |
+
if "zh_CN" in locale_filename:
|
100 |
+
continue
|
101 |
+
locale_strs = get_locale_strings(locale_filename)
|
102 |
+
|
103 |
+
# Add new keys
|
104 |
+
new_keys = []
|
105 |
+
for key in current_strs:
|
106 |
+
if key not in locale_strs:
|
107 |
+
new_keys.append(key)
|
108 |
+
locale_strs[key] = ""
|
109 |
+
print(f"{locale_filename[7:-5]}'s new str: {len(new_keys)}")
|
110 |
+
# Add (NOT USED) to invalid keys
|
111 |
+
for key in locale_strs:
|
112 |
+
if key not in current_strs:
|
113 |
+
locale_strs[key] = "(🔴NOT USED)" + locale_strs[key]
|
114 |
+
print(f"{locale_filename[7:-5]}'s invalid str: {len(locale_strs) - len(current_strs)}")
|
115 |
+
|
116 |
+
locale_strs = sort_strings(locale_strs)
|
117 |
+
|
118 |
+
if auto:
|
119 |
+
tasks = []
|
120 |
+
non_translated_keys = []
|
121 |
+
for key in locale_strs:
|
122 |
+
if locale_strs[key] == "":
|
123 |
+
non_translated_keys.append(key)
|
124 |
+
tasks.append(auto_translate(key, locale_filename[7:-5]))
|
125 |
+
results = await asyncio.gather(*tasks)
|
126 |
+
for key, result in zip(non_translated_keys, results):
|
127 |
+
locale_strs[key] = "(🟡REVIEW NEEDED)" + result
|
128 |
+
print(f"{locale_filename[7:-5]}'s auto translated str: {len(non_translated_keys)}")
|
129 |
+
|
130 |
+
with open(locale_filename, 'w', encoding='utf-8') as f:
|
131 |
+
json.dump(locale_strs, f, ensure_ascii=False, indent=4)
|
132 |
+
|
133 |
+
|
134 |
+
if __name__ == "__main__":
|
135 |
+
auto = False
|
136 |
+
if len(sys.argv) > 1 and sys.argv[1] == "--auto":
|
137 |
+
auto = True
|
138 |
+
asyncio.run(main(auto))
|
locale/ja_JP.json
CHANGED
@@ -1,87 +1,141 @@
|
|
1 |
{
|
2 |
-
"
|
3 |
-
"
|
4 |
-
"🧹 新的对话": "🧹 新しい会話",
|
5 |
-
"🔄 重新生成": "🔄 再生成",
|
6 |
-
"🗑️ 删除最旧对话": "🗑️ 最古の会話削除",
|
7 |
-
"🗑️ 删除最新对话": "🗑️ 最新の会話削除",
|
8 |
-
"模型": "LLMモデル",
|
9 |
-
"多账号模式已开启,无需输入key,可直接开始对话": "複数アカウントモードがオンになっています。キーを入力する必要はありません。会話を開始できます",
|
10 |
"**发送消息** 或 **提交key** 以显示额度": "**メッセージを送信** または **キーを送信** して、クレジットを表示します",
|
11 |
-
"
|
12 |
-
"
|
13 |
-
"
|
14 |
-
"
|
15 |
-
"
|
16 |
-
"
|
17 |
-
"
|
18 |
-
"
|
19 |
-
"
|
20 |
-
"
|
21 |
-
"
|
22 |
-
"
|
23 |
-
"
|
|
|
|
|
|
|
|
|
|
|
24 |
"从Prompt模板中加载": "Promptテンプレートから読込",
|
25 |
-
"保存/加载": "保存/読込",
|
26 |
-
"保存/加载对话历史记录": "会話履歴を保存/読込",
|
27 |
"从列表中加载对话": "リストから会話を読込",
|
28 |
-
"设置文件名: 默认为.json,可选为.md": "ファイル名を設定: デフォルトは.json、.mdを選択できます",
|
29 |
-
"设置保存文件名": "保存ファイル名を設定",
|
30 |
-
"对话历史记录": "会話履歴",
|
31 |
-
"💾 保存对话": "💾 会話を保存",
|
32 |
-
"📝 导出为Markdown": "📝 Markdownでエクスポート",
|
33 |
-
"默认保存于history文件夹": "デフォルトでhistoryフォルダに保存されます",
|
34 |
-
"高级": "Advanced",
|
35 |
-
"# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ 変更には慎重に ⚠️",
|
36 |
-
"参数": "パラメータ",
|
37 |
-
"停止符,用英文逗号隔开...": "ここにストップ文字を英語のカンマで区切って入力してください...",
|
38 |
-
"用于定位滥用行为": "不正行為を特定するために使用されます",
|
39 |
-
"用户名": "ユーザー名",
|
40 |
-
"在这里输入API-Host...": "API-Hostを入力してください...",
|
41 |
-
"🔄 切换API地址": "🔄 APIアドレスを切り替え",
|
42 |
-
"未设置代理...": "代理が設定されていません...",
|
43 |
"代理地址": "プロキシアドレス",
|
44 |
-
"
|
45 |
-
"
|
46 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
"取消": "キャンセル",
|
48 |
-
"
|
49 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
"好": "はい",
|
51 |
-
"
|
52 |
-
"
|
|
|
|
|
|
|
|
|
|
|
53 |
"川虎Chat 🚀": "川虎Chat 🚀",
|
|
|
|
|
54 |
"开始实时传输回答……": "ストリーム出力開始……",
|
55 |
-
"
|
56 |
-
"
|
57 |
-
"
|
58 |
-
"
|
59 |
-
"
|
60 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
"本月使用金额": "今月の使用料金",
|
62 |
-
"
|
63 |
-
"
|
64 |
-
"
|
|
|
|
|
65 |
"模型设置为了:": "LLMモデルを設定しました: ",
|
66 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
"获取对话时发生错误,请查看后台日志": "会話取得時にエラー発生、あとのログを確認してください",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
"请检查网络连接,或者API-Key是否有效。": "ネットワーク接続を確認するか、APIキーが有効かどうかを確認してください。",
|
69 |
-
"连接超时,无法获取对话。": "接続タイムアウト、会話を取得できません。",
|
70 |
-
"读取超时,无法获取对话。": "読み込みタイムアウト、会話を取得できません。",
|
71 |
-
"代理错误,无法获取对话。": "プロキシエラー、会話を取得できません。",
|
72 |
-
"SSL错误,无法获取对话。": "SSLエラー、会話を取得できません。",
|
73 |
-
"API key为空,请检查是否输入正确。": "APIキーが入力されていません。正しく入力されているか確認してください。",
|
74 |
"请输入对话内容。": "会話内容を入力してください。",
|
|
|
|
|
75 |
"账单信息不适用": "課金情報は対象外です",
|
76 |
-
"
|
77 |
-
"
|
78 |
-
"
|
79 |
-
"
|
80 |
-
"
|
81 |
-
"
|
82 |
-
"
|
83 |
-
"
|
84 |
-
"
|
85 |
-
"
|
86 |
-
"
|
87 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
{
|
2 |
+
" 吗?": " を削除してもよろしいですか?",
|
3 |
+
"# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ 変更には慎重に ⚠️",
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
"**发送消息** 或 **提交key** 以显示额度": "**メッセージを送信** または **キーを送信** して、クレジットを表示します",
|
5 |
+
"**本月使用金额** ": "**今月の使用料金** ",
|
6 |
+
"**获取API使用情况失败**": "**API使用状況の取得に失敗しました**",
|
7 |
+
"**获取API使用情况失败**,sensitive_id错误或已过期": "**API使用状況の取得に失敗しました**、sensitive_idが間違っているか、期限切れです",
|
8 |
+
"**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**API使用状況の取得に失敗しました**、`config.json`に正しい`sensitive_id`を入力する必要があります",
|
9 |
+
"API key为空,请检查是否输入正确。": "APIキーが入力されていません。正しく入力されているか確認してください。",
|
10 |
+
"API密钥更改为了": "APIキーが変更されました",
|
11 |
+
"JSON解析错误,收到的内容: ": "JSON解析エラー、受信内容: ",
|
12 |
+
"SSL错误,无法获取对话。": "SSLエラー、会話を取得できません。",
|
13 |
+
"Token 计数: ": "Token数: ",
|
14 |
+
"☹️发生了错误:": "エラーが発生しました: ",
|
15 |
+
"⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "⚠️ APIキーの安全性を確保するために、`config.json`ファイルでネットワーク設定を変更してください。",
|
16 |
+
"。你仍然可以使用聊天功能。": "。あなたはまだチャット機能を使用できます。",
|
17 |
+
"上传": "アップロード",
|
18 |
+
"上传了": "アップロードしました。",
|
19 |
+
"上传到 OpenAI 后自动填充": "OpenAIへのアップロード後、自動的に入力されます",
|
20 |
+
"上传到OpenAI": "OpenAIへのアップロード",
|
21 |
+
"上传文件": "ファイルをアップロード",
|
22 |
+
"仅供查看": "閲覧専用",
|
23 |
"从Prompt模板中加载": "Promptテンプレートから読込",
|
|
|
|
|
24 |
"从列表中加载对话": "リストから会話を読込",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
"代理地址": "プロキシアドレス",
|
26 |
+
"代理��误,无法获取对话。": "プロキシエラー、会話を取得できません。",
|
27 |
+
"你没有权限访问 GPT4,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)": "GPT-4にアクセス権がありません、[詳細はこちら](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)",
|
28 |
+
"你没有选择任何对话历史": "あなたは何の会話履歴も選択していません。",
|
29 |
+
"你真的要删除 ": "本当に ",
|
30 |
+
"使用在线搜索": "オンライン検索を使用",
|
31 |
+
"停止符,用英文逗号隔开...": "ここにストップ文字を英語のカンマで区切って入力してください...",
|
32 |
+
"关于": "について",
|
33 |
+
"准备数据集": "データセットの準備",
|
34 |
+
"切换亮暗色主题": "テーマの明暗切替",
|
35 |
+
"删除对话历史成功": "削除した会話の履歴",
|
36 |
+
"删除这轮问答": "この質疑応答を削除",
|
37 |
+
"刷新状态": "ステータスを更新",
|
38 |
+
"剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)": "剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)",
|
39 |
+
"加载Prompt模板": "Promptテンプレートを読込",
|
40 |
+
"单轮对话": "単発会話",
|
41 |
+
"历史记录(JSON)": "履歴ファイル(JSON)",
|
42 |
+
"参数": "パラメータ",
|
43 |
+
"双栏pdf": "2カラムpdf",
|
44 |
"取消": "キャンセル",
|
45 |
+
"取消所有任务": "すべてのタスクをキャンセル",
|
46 |
+
"可选,用于区分不同的模型": "オプション、異なるモデルを区別するために使用",
|
47 |
+
"启用的工具:": "有効なツール:",
|
48 |
+
"在工具箱中管理知识库文件": "ツールボックスでナレッジベースファイルの管理を行う",
|
49 |
+
"在线搜索": "オンライン検索",
|
50 |
+
"在这里输入": "ここに入力",
|
51 |
+
"在这里输入System Prompt...": "System Promptを入力してください...",
|
52 |
+
"多账号模式已开启,无需输入key,可直接开始对话": "複数アカウントモードがオンになっています。キーを入力する必要はありません。会話を開始できます",
|
53 |
"好": "はい",
|
54 |
+
"实时传输回答": "ストリーム出力",
|
55 |
+
"对话": "会話",
|
56 |
+
"对话历史": "対話履歴",
|
57 |
+
"对话历史记录": "会話履歴",
|
58 |
+
"对话命名方式": "会話の命名方法",
|
59 |
+
"导出为 Markdown": "Markdownでエクスポート",
|
60 |
+
"川虎Chat": "川虎Chat",
|
61 |
"川虎Chat 🚀": "川虎Chat 🚀",
|
62 |
+
"工具箱": "ツールボックス",
|
63 |
+
"已经被删除啦": "削除されました。",
|
64 |
"开始实时传输回答……": "ストリーム出力開始……",
|
65 |
+
"开始训练": "トレーニングを開始",
|
66 |
+
"微调": "ファインチューニング",
|
67 |
+
"总结": "要約する",
|
68 |
+
"总结完成": "完了",
|
69 |
+
"您使用的就是最新版!": "最新バージョンを使用しています!",
|
70 |
+
"您的IP区域:": "あなたのIPアドレス地域:",
|
71 |
+
"您的IP区域:未知。": "あなたのIPアドレス地域:不明",
|
72 |
+
"拓展": "拡張",
|
73 |
+
"搜索(支持正则)...": "検索(正規表現をサポート)...",
|
74 |
+
"数据集预览": "データセットのプレビュー",
|
75 |
+
"文件ID": "ファイルID",
|
76 |
+
"新对话 ": "新しい会話 ",
|
77 |
+
"新建对话保留Prompt": "新しい会話を作成してください。プロンプトを保留します。",
|
78 |
+
"暂时未知": "しばらく不明である",
|
79 |
+
"更新": "アップデート",
|
80 |
+
"更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "更新に失敗しました、[手動での更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)をお試しください。",
|
81 |
+
"更新成功,请重启本程序": "更新が成功しました、このプログラムを再起動してください",
|
82 |
+
"未命名对话历史记录": "名無しの会話履歴",
|
83 |
+
"未设置代理...": "代理が設定されていません...",
|
84 |
"本月使用金额": "今月の使用料金",
|
85 |
+
"查看[使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)": "[使用ガイド](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)を表示",
|
86 |
+
"根据日期时间": "日付と時刻に基づいて",
|
87 |
+
"模型": "LLMモデル",
|
88 |
+
"模型名称后缀": "モデル名のサフィックス",
|
89 |
+
"模型自动总结(消耗tokens)": "モデルによる自動要約(トークン消費)",
|
90 |
"模型设置为了:": "LLMモデルを設定しました: ",
|
91 |
+
"正在尝试更新...": "更新を試みています...",
|
92 |
+
"添加训练好的模型到模型列表": "トレーニング済みモデルをモデルリストに追加",
|
93 |
+
"状态": "ステータス",
|
94 |
+
"生成内容总结中……": "コンテンツ概要を生成しています...",
|
95 |
+
"用于定位滥用行为": "不正行為を特定するために使用されます",
|
96 |
+
"用户名": "ユーザー名",
|
97 |
+
"由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最新コードは川虎Chatのサイトへ [GitHubプロジェクト](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
|
98 |
+
"知识库": "ナレッジベース",
|
99 |
+
"知识库文件": "ナレッジベースファイル",
|
100 |
+
"第一条提问": "最初の質問",
|
101 |
+
"索引构建完成": "索引の構築が完了しました。",
|
102 |
+
"网络": "ネットワーク",
|
103 |
+
"获取API使用情况失败:": "API使用状況の取得に失敗しました:",
|
104 |
+
"获取IP地理位置失败。原因:": "IPアドレス地域の取得に失敗しました。理由:",
|
105 |
"获取对话时发生错误,请查看后台日志": "会話取得時にエラー発生、あとのログを確認してください",
|
106 |
+
"训练": "トレーニング",
|
107 |
+
"训练状态": "トレーニングステータス",
|
108 |
+
"训练轮数(Epochs)": "トレーニングエポック数",
|
109 |
+
"设置": "設定",
|
110 |
+
"设置保存文件名": "保存ファイル名を設定",
|
111 |
+
"设置文件名: 默认为.json,可选为.md": "ファイル名を設定: デフォルトは.json、.mdを選択できます",
|
112 |
+
"识别公式": "formula OCR",
|
113 |
+
"详情": "詳細",
|
114 |
+
"请查看 config_example.json,配置 Azure OpenAI": "Azure OpenAIの設定については、config_example.jsonをご覧ください",
|
115 |
"请检查网络连接,或者API-Key是否有效。": "ネットワーク接続を確認するか、APIキーが有効かどうかを確認してください。",
|
|
|
|
|
|
|
|
|
|
|
116 |
"请输入对话内容。": "会話内容を入力してください。",
|
117 |
+
"请输入有效的文件名,不要包含以下特殊字符:": "有効なファイル名を入力してください。以下の特殊文字は使用しないでください:",
|
118 |
+
"读取超时,无法获取对话。": "読み込みタイムアウト、会話を取得できません。",
|
119 |
"账单信息不适用": "課金情報は対象外です",
|
120 |
+
"连接超时,无法获取对话。": "接続タイムアウト、会話を取得できません。",
|
121 |
+
"选择LoRA模型": "LoRAモデルを選択",
|
122 |
+
"选择Prompt模板集合文件": "Promptテンプレートコレクションを選択",
|
123 |
+
"选择回复语言(针对搜索&索引功能)": "回答言語を選択(検索とインデックス機能に対して)",
|
124 |
+
"选择数据集": "データセットの選択",
|
125 |
+
"选择模型": "LLMモデルを選択",
|
126 |
+
"重命名该对话": "会話の名前を変更",
|
127 |
+
"重新生成": "再生成",
|
128 |
+
"高级": "Advanced",
|
129 |
+
",本次对话累计消耗了 ": ", 今の会話で消費合計 ",
|
130 |
+
"💾 保存对话": "💾 会話を保存",
|
131 |
+
"📝 导出为 Markdown": "📝 Markdownにエクスポート",
|
132 |
+
"🔄 切换API地址": "🔄 APIアドレスを切り替え",
|
133 |
+
"🔄 刷新": "🔄 更新",
|
134 |
+
"🔄 检查更新...": "🔄 アップデートをチェック...",
|
135 |
+
"🔄 设置代理地址": "🔄 プロキシアドレスを設定",
|
136 |
+
"🔄 重新生成": "🔄 再生成",
|
137 |
+
"🔙 恢复默认网络设置": "🔙 ネットワーク設定のリセット",
|
138 |
+
"🗑️ 删除最新对话": "🗑️ 最新の会話削除",
|
139 |
+
"🗑️ 删除最旧对话": "🗑️ 最古の会話削除",
|
140 |
+
"🧹 新的对话": "🧹 新しい会話"
|
141 |
+
}
|
locale/ko_KR.json
CHANGED
@@ -1,89 +1,141 @@
|
|
1 |
{
|
2 |
-
"
|
3 |
-
"
|
4 |
-
"🧹 新的对话": "🧹 새로운 대화",
|
5 |
-
"🔄 重新生成": "🔄 재생성",
|
6 |
-
"🗑️ 删除最旧对话": "🗑️ 가장 오래된 대화 삭제",
|
7 |
-
"🗑️ 删除最新对话": "🗑️ 최신 대화 삭제",
|
8 |
-
"🗑️ 删除": "🗑️ 삭제",
|
9 |
-
"模型": "LLM 모델",
|
10 |
-
"多账号模式已开启,无需输入key,可直接开始对话": "다중 계정 모드가 활성화되어 있으므로 키를 입력할 필요가 없이 바로 대화를 시작할 수 있습니다",
|
11 |
"**发送消息** 或 **提交key** 以显示额度": "**메세지를 전송** 하거나 **Key를 입력**하여 크레딧 표시",
|
12 |
-
"
|
13 |
-
"
|
14 |
-
"
|
15 |
-
"
|
16 |
-
"
|
17 |
-
"
|
18 |
-
"
|
19 |
-
"
|
20 |
-
"
|
21 |
-
"
|
22 |
-
"
|
23 |
-
"
|
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 |
-
"在这里输入API-Host...": "여기에 API host를 입력하세요...",
|
42 |
-
"🔄 切换API地址": "🔄 API 주소 변경",
|
43 |
-
"未设置代理...": "대리인이 설정되지 않았습니다...",
|
44 |
"代理地址": "프록시 주소",
|
45 |
-
"
|
46 |
-
"
|
47 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
"取消": "취소",
|
49 |
-
"
|
50 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
"好": "예",
|
52 |
-
"
|
53 |
-
"
|
|
|
|
|
|
|
|
|
|
|
54 |
"川虎Chat 🚀": "Chuanhu Chat 🚀",
|
|
|
|
|
55 |
"开始实时传输回答……": "실시간 응답 출력 시작...",
|
56 |
-
"
|
57 |
-
"
|
58 |
-
"
|
59 |
-
"
|
60 |
-
"
|
61 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
"本月使用金额": "이번 달 사용금액",
|
63 |
-
"
|
64 |
-
"
|
65 |
-
"
|
|
|
|
|
66 |
"模型设置为了:": "설정된 모델: ",
|
67 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
"获取对话时发生错误,请查看后台日志": "대화를 가져오는 중 에러가 발생했습니다. 백그라운드 로그를 확인하세요",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
"请检查网络连接,或者API-Key是否有效。": "네트워크 연결 또는 API키가 유효한지 확인하세요",
|
70 |
-
"连接超时,无法获取对话。": "연결 시간 초과, 대화를 가져올 수 없습니다.",
|
71 |
-
"读取超时,无法获取对话。": "읽기 시간 초과, 대화를 가져올 수 없습니다.",
|
72 |
-
"代理错误,无法获取对话。": "프록시 에러, 대화를 가져올 수 없습니다.",
|
73 |
-
"SSL错误,无法获取对话。": "SSL 에러, 대화를 가져올 수 없습니다.",
|
74 |
-
"API key为空,请检查是否输入正确。": "API 키가 비어 있습니다. 올바르게 입력되었는지 확인하십세요.",
|
75 |
"请输入对话内容。": "대화 내용을 입력하세요.",
|
|
|
|
|
76 |
"账单信息不适用": "청구 정보를 가져올 수 없습니다",
|
77 |
-
"
|
78 |
-
"
|
79 |
-
"
|
80 |
-
"
|
81 |
-
"
|
82 |
-
"
|
83 |
-
"
|
84 |
-
"
|
85 |
-
"
|
86 |
-
"
|
87 |
-
"
|
88 |
-
"
|
89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
{
|
2 |
+
" 吗?": " 을(를) 삭제하시겠습니까?",
|
3 |
+
"# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ 주의: 변경시 주의하세요. ⚠️",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
"**发送消息** 或 **提交key** 以显示额度": "**메세지를 전송** 하거나 **Key를 입력**하여 크레딧 표시",
|
5 |
+
"**本月使用金额** ": "**이번 달 사용금액** ",
|
6 |
+
"**获取API使用情况失败**": "**API 사용량 가져오기 실패**",
|
7 |
+
"**获取API使用情况失败**,sensitive_id错误或已过期": "**API 사용량 가져오기 실패**. sensitive_id가 잘못되었거나 만료되었습니다",
|
8 |
+
"**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**API 사용량 가져오기 실패**. `config.json`에 올바른 `sensitive_id`를 입력해야 합니다",
|
9 |
+
"API key为空,请检查是否输入正确。": "API 키가 비어 있습니다. 올바르게 입력되었는지 확인하십세요.",
|
10 |
+
"API密钥更改为了": "API 키가 변경되었습니다.",
|
11 |
+
"JSON解析错误,收到的内容: ": "JSON 파싱 에러, 응답: ",
|
12 |
+
"SSL错误,无法获取对话。": "SSL 에러, 대화를 가져올 수 없습니다.",
|
13 |
+
"Token 计数: ": "토큰 수: ",
|
14 |
+
"☹️发生了错误:": "☹️에러: ",
|
15 |
+
"⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "⚠️ API-Key의 안전을 보장하기 위해 네트워크 설정을 `config.json` 구성 파일에서 수정해주세요.",
|
16 |
+
"。你仍然可以使用聊天功能。": ". 채팅 기능을 계속 사용할 수 있습니다.",
|
17 |
+
"上传": "업로드",
|
18 |
+
"上传了": "업로드되었습니다.",
|
19 |
+
"上传到 OpenAI 后自动填充": "OpenAI로 업로드한 후 자동으로 채워집니다",
|
20 |
+
"上传到OpenAI": "OpenAI로 업로드",
|
21 |
+
"上传文件": "파일 업로드",
|
22 |
+
"仅供查看": "읽기 전용",
|
23 |
"从Prompt模板中加载": "프롬프트 템플릿에서 불러오기",
|
|
|
|
|
24 |
"从列表中加载对话": "리스트에서 대화 불러오기",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
"代理地址": "프록시 주소",
|
26 |
+
"代理错误,无法获取对话。": "프록시 에러, 대화를 가져올 수 없습니다.",
|
27 |
+
"你没有权限访问 GPT4,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)": "GPT-4에 접근 권한이 없습니다. [자세히 알아보기](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)",
|
28 |
+
"你没有选择任何对话历史": "대화 기록을 선택하지 않았습니다.",
|
29 |
+
"你真的要删除 ": "정말로 ",
|
30 |
+
"使用在线搜索": "온라인 검색 사용",
|
31 |
+
"停止符,用英文逗号隔开...": "여기에 정지 토큰 입력, ','로 구분됨...",
|
32 |
+
"关于": "관련",
|
33 |
+
"准备数据集": "데이터셋 준비",
|
34 |
+
"切换亮暗色主题": "라이트/다크 테마 전환",
|
35 |
+
"删除对话历史成功": "대화 기록이 성공적으로 삭제되었습니다.",
|
36 |
+
"删除这轮问答": "이 라운드의 질문과 답변 삭제",
|
37 |
+
"刷新状态": "상태 새로 고침",
|
38 |
+
"剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)": "남은 할당량이 부족합니다. [자세한 내용](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)을 확인하세요.",
|
39 |
+
"加载Prompt模板": "프롬프트 템플릿 불러오기",
|
40 |
+
"单轮对话": "단일 대화",
|
41 |
+
"历史记录(JSON)": "기록 파일 (JSON)",
|
42 |
+
"参数": "파라미터들",
|
43 |
+
"双栏pdf": "2-column pdf",
|
44 |
"取消": "취소",
|
45 |
+
"取消所有任务": "모든 작업 취소",
|
46 |
+
"可选,用于区分不同的模型": "선택 사항, 다른 모델을 구분하는 데 사용",
|
47 |
+
"启用的工具:": "활성화된 도구: ",
|
48 |
+
"在工具箱中管理知识库文件": "지식 라이브러리 파일을 도구 상자에서 관리",
|
49 |
+
"在线搜索": "온라인 검색",
|
50 |
+
"在这里输入": "여기에 입력하세요",
|
51 |
+
"在这里输入System Prompt...": "여기에 시스템 프롬프트를 입력하세요...",
|
52 |
+
"多账号模式已开启,无需输入key,可直接开始对话": "다중 계정 모드가 활성화되어 있으므로 키를 입력할 필요가 없이 바로 대화를 시작할 수 있습니다",
|
53 |
"好": "예",
|
54 |
+
"实时传输回答": "실시간 전송",
|
55 |
+
"对话": "대화",
|
56 |
+
"对话历史": "대화 내역",
|
57 |
+
"对话历史记录": "대화 기록",
|
58 |
+
"对话命名方式": "대화 이름 설정",
|
59 |
+
"导出为 Markdown": "마크다운으로 내보내기",
|
60 |
+
"川虎Chat": "Chuanhu Chat",
|
61 |
"川虎Chat 🚀": "Chuanhu Chat 🚀",
|
62 |
+
"工具箱": "도구 상자",
|
63 |
+
"已经被删除啦": "이미 삭제되었습니다.",
|
64 |
"开始实时传输回答……": "실시간 응답 출력 시작...",
|
65 |
+
"开始训练": "훈련 시작",
|
66 |
+
"微调": "미세 조정",
|
67 |
+
"总结": "요약",
|
68 |
+
"总结完成": "작업 완료",
|
69 |
+
"您使用的就是最新版!": "최신 버전을 사용하고 있습니다!",
|
70 |
+
"您的IP区域:": "당신의 IP 지역: ",
|
71 |
+
"您的IP区域:未知。": "IP 지역: 알 수 없음.",
|
72 |
+
"拓展": "확장",
|
73 |
+
"搜索(支持正则)...": "검색 (정규식 지원)...",
|
74 |
+
"数据集预览": "데이터셋 미리보기",
|
75 |
+
"文件ID": "파일 ID",
|
76 |
+
"新对话 ": "새 대화 ",
|
77 |
+
"新建对话保留Prompt": "새 대화 생성, 프롬프트 유지하기",
|
78 |
+
"暂时未知": "알 수 없음",
|
79 |
+
"更新": "업데이트",
|
80 |
+
"更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "업데이트 실패, [수동 업데이트](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)를 시도하십시오",
|
81 |
+
"更新成功,请重启本程序": "업데이트 성공, 이 프로그램을 재시작 해주세요",
|
82 |
+
"未命名对话历史记录": "이름없는 대화 기록",
|
83 |
+
"未设置代理...": "대리인이 설정되지 않았습니다...",
|
84 |
"本月使用金额": "이번 달 사용금액",
|
85 |
+
"查看[使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)": "[사용 가이드](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35) 보기",
|
86 |
+
"根据日期时间": "날짜 및 시간 기준",
|
87 |
+
"模型": "LLM 모델",
|
88 |
+
"模型名称后缀": "모델 이름 접미사",
|
89 |
+
"模型自动总结(消耗tokens)": "모델에 의한 자동 요약 (토큰 소비)",
|
90 |
"模型设置为了:": "설정된 모델: ",
|
91 |
+
"正在尝试更新...": "업데이트를 시도 중...",
|
92 |
+
"添加训练好的模型到模型列表": "훈련된 모델을 모델 목록에 추가",
|
93 |
+
"状态": "상태",
|
94 |
+
"生成内容总结中……": "콘텐츠 요약 생성중...",
|
95 |
+
"用于定位滥用行为": "악용 사례 파악에 활용됨",
|
96 |
+
"用户名": "사용자 이름",
|
97 |
+
"由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)",
|
98 |
+
"知识库": "지식 라이브러리",
|
99 |
+
"知识库文件": "지식 라이브러리 파일",
|
100 |
+
"第一条提问": "첫 번째 질문",
|
101 |
+
"索引构建完成": "인덱스 구축이 완료되었습니다.",
|
102 |
+
"网络": "네트워크",
|
103 |
+
"获取API使用情况失败:": "API 사용량 가져오기 실패:",
|
104 |
+
"获取IP地理位置失败。原因:": "다음과 같은 이유로 IP 위치를 가져올 수 없습니다. 이유: ",
|
105 |
"获取对话时发生错误,请查看后台日志": "대화를 가져오는 중 에러가 발생했습니다. 백그라운드 로그를 확인하세요",
|
106 |
+
"训练": "훈련",
|
107 |
+
"训练状态": "훈련 상태",
|
108 |
+
"训练轮数(Epochs)": "훈련 라운드(Epochs)",
|
109 |
+
"设置": "설정",
|
110 |
+
"设置保存文件名": "저장 파일명 설정",
|
111 |
+
"设置文件名: 默认为.json,可选为.md": "파일 이름 설정: 기본값: .json, 선택: .md",
|
112 |
+
"识别公式": "formula OCR",
|
113 |
+
"详情": "상세",
|
114 |
+
"请查看 config_example.json,配置 Azure OpenAI": "Azure OpenAI 설정을 확인하세요",
|
115 |
"请检查网络连接,或者API-Key是否有效。": "네트워크 연결 또는 API키가 유효한지 확인하세요",
|
|
|
|
|
|
|
|
|
|
|
116 |
"请输入对话内容。": "대화 내용을 입력하세요.",
|
117 |
+
"请输入有效的文件名,不要包含以下特殊字符:": "유효한 파일 이름을 입력하세요. 다음 특수 문자는 포함하지 마세요: ",
|
118 |
+
"读取超时,无法获取对话。": "읽기 시간 초과, 대화를 가져올 수 없습니다.",
|
119 |
"账单信息不适用": "청구 정보를 가져올 수 없습니다",
|
120 |
+
"连接超时,无法获取对话。": "연결 시간 초과, 대화를 가져올 수 없습니다.",
|
121 |
+
"选择LoRA模型": "LoRA 모델 선택",
|
122 |
+
"选择Prompt模板集合文件": "프롬프트 콜렉션 파일 선택",
|
123 |
+
"选择回复语言(针对搜索&索引功能)": "답장 언어 선택 (검색 & 인덱스용)",
|
124 |
+
"选择数据集": "데이터셋 선택",
|
125 |
+
"选择模型": "모델 선택",
|
126 |
+
"重命名该对话": "대화 이름 변경",
|
127 |
+
"重新生成": "재생성",
|
128 |
+
"高级": "고급",
|
129 |
+
",本次对话累计消耗了 ": ",이 대화의 전체 비용은 ",
|
130 |
+
"💾 保存对话": "💾 대화 저장",
|
131 |
+
"📝 导出为 Markdown": "📝 마크다운으로 내보내기",
|
132 |
+
"🔄 切换API地址": "🔄 API 주소 변경",
|
133 |
+
"🔄 刷新": "🔄 새로고침",
|
134 |
+
"🔄 检查更新...": "🔄 업데이트 확인...",
|
135 |
+
"🔄 设置代理地址": "🔄 프록시 주소 설정",
|
136 |
+
"🔄 重新生成": "🔄 재생성",
|
137 |
+
"🔙 恢复默认网络设置": "🔙 네트워크 설정 초기화",
|
138 |
+
"🗑️ 删除最新对话": "🗑️ 최신 대화 삭제",
|
139 |
+
"🗑️ 删除最旧对话": "🗑️ 가장 오래된 대화 삭제",
|
140 |
+
"🧹 新的对话": "🧹 새로운 대화"
|
141 |
+
}
|
locale/ru_RU.json
ADDED
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
" 吗?": " ?",
|
3 |
+
"# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ ВНИМАНИЕ: ИЗМЕНЯЙТЕ ОСТОРОЖНО ⚠️",
|
4 |
+
"**发送消息** 或 **提交key** 以显示额度": "**Отправить сообщение** или **отправить ключ** для отображения лимита",
|
5 |
+
"**本月使用金额** ": "**Использовано средств в этом месяце**",
|
6 |
+
"**获取API使用情况失败**": "**Не удалось получить информацию об использовании API**",
|
7 |
+
"**获取API使用情况失败**,sensitive_id错误或已过期": "**Не удалось получить информацию об использовании API**, ошибка sensitive_id или истек срок действия",
|
8 |
+
"**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**Не удалось получить информацию об использовании API**, необходимо правильно заполнить sensitive_id в `config.json`",
|
9 |
+
"API key为空,请检查是否输入正确。": "Пустой API-Key, пожалуйста, проверьте правильность ввода.",
|
10 |
+
"API密钥更改为了": "Ключ API изменен на",
|
11 |
+
"JSON解析错误,收到的内容: ": "Ошибка анализа JSON, полученный контент:",
|
12 |
+
"SSL错误,无法获取对话。": "Ошибка SSL, не удалось получить диалог.",
|
13 |
+
"Token 计数: ": "Использованно токенов: ",
|
14 |
+
"☹️发生了错误:": "☹️ Произошла ошибка:",
|
15 |
+
"⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "⚠️ Для обеспечения безопасности API-Key, измените настройки сети в файле конфигурации `config.json`",
|
16 |
+
"。你仍然可以使用聊天功能。": ". Вы все равно можете использовать функцию чата.",
|
17 |
+
"上传": "Загрузить",
|
18 |
+
"上传了": "Загрузка завершена.",
|
19 |
+
"上传到 OpenAI 后自动填充": "Автоматическое заполнение после загрузки в OpenAI",
|
20 |
+
"上传到OpenAI": "Загрузить в OpenAI",
|
21 |
+
"上传文件": "Загрузить файл",
|
22 |
+
"仅供查看": "Только для просмотра",
|
23 |
+
"从Prompt模板中加载": "Загрузить из шаблона Prompt",
|
24 |
+
"从列表中加载对话": "Загрузить диалог из списка",
|
25 |
+
"代理地址": "Адрес прокси",
|
26 |
+
"代理错误,无法获取对话。": "Ошибка прокси, не удалось получить диалог.",
|
27 |
+
"你没有权限访问 GPT4,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)": "У вас нет доступа к GPT4, [подробнее](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)",
|
28 |
+
"你没有选择任何对话历史": "Вы не выбрали никакой истории переписки",
|
29 |
+
"你真的要删除 ": "Вы уверены, что хотите удалить ",
|
30 |
+
"使用在线搜索": "Использовать онлайн-поиск",
|
31 |
+
"停止符,用英文逗号隔开...": "Разделительные символы, разделенные запятой...",
|
32 |
+
"关于": "О программе",
|
33 |
+
"准备数据集": "Подготовка набора данных",
|
34 |
+
"切换亮暗色主题": "Переключить светлую/темную тему",
|
35 |
+
"删除对话历史成功": "Успешно удалена история переписки.",
|
36 |
+
"删除这轮问答": "Удалить этот раунд вопросов и ответов",
|
37 |
+
"刷新状态": "Обновить статус",
|
38 |
+
"剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)": "剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)",
|
39 |
+
"加载Prompt模板": "Загрузить шаблон Prompt",
|
40 |
+
"单轮对话": "Одиночный диалог",
|
41 |
+
"历史记录(JSON)": "Файл истории (JSON)",
|
42 |
+
"参数": "Параметры",
|
43 |
+
"双栏pdf": "Двухколоночный PDF",
|
44 |
+
"取消": "Отмена",
|
45 |
+
"取消所有任务": "Отменить все задачи",
|
46 |
+
"可选,用于区分不同的模型": "Необязательно, используется для различения разных моделей",
|
47 |
+
"启用的工具:": "Включенные инструменты:",
|
48 |
+
"在工具箱中管理知识库文件": "Управление файлами базы знаний в инструментах",
|
49 |
+
"在线搜索": "Онлайн-поиск",
|
50 |
+
"在这里输入": "Введите здесь",
|
51 |
+
"在这里输入System Prompt...": "Введите здесь системное подсказку...",
|
52 |
+
"多账号模式已开启,无需输入key,可直接开始对话": "Режим множественных аккаунтов включен, не требуется ввод ключа, можно сразу начать диалог",
|
53 |
+
"好": "Хорошо",
|
54 |
+
"实时传输回答": "Передача ответа в реальном времени",
|
55 |
+
"对话": "Диалог",
|
56 |
+
"对话历史": "Диалоговая история",
|
57 |
+
"对话历史记录": "История диалога",
|
58 |
+
"对话命名方式": "Способ названия диалога",
|
59 |
+
"导出为 Markdown": "Экспортировать в Markdown",
|
60 |
+
"川虎Chat": "Chuanhu Чат",
|
61 |
+
"川虎Chat 🚀": "Chuanhu Чат 🚀",
|
62 |
+
"工具箱": "Инструменты",
|
63 |
+
"已经被删除啦": "Уже удалено.",
|
64 |
+
"开始实时传输回答……": "Начните трансляцию ответов в режиме реального времени...",
|
65 |
+
"开始训练": "Начать обучение",
|
66 |
+
"微调": "Своя модель",
|
67 |
+
"总结": "Подведение итога",
|
68 |
+
"总结完成": "Готово",
|
69 |
+
"您使用的就是最新版!": "Вы используете последнюю версию!",
|
70 |
+
"您的IP区域:": "Ваша IP-зона:",
|
71 |
+
"您的IP区域:未知。": "Ваша IP-зона: неизвестно.",
|
72 |
+
"拓展": "Расширенные настройки",
|
73 |
+
"搜索(支持正则)...": "Поиск (поддержка регулярности)...",
|
74 |
+
"数据集预览": "Предпросмотр набора данных",
|
75 |
+
"文件ID": "Идентификатор файла",
|
76 |
+
"新对话 ": "Новый диалог ",
|
77 |
+
"新建对话保留Prompt": "Создать диалог с сохранением подсказки",
|
78 |
+
"暂时未知": "Временно неизвестно",
|
79 |
+
"更新": "Обновить",
|
80 |
+
"更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "Обновление не удалось, пожалуйста, попробуйте обновить вручную",
|
81 |
+
"更新成功,请重启本程序": "Обновление успешно, пожалуйста, перезапустите программу",
|
82 |
+
"未命名对话历史记录": "Безымянная история диалога",
|
83 |
+
"未设置代理...": "Прокси не настроен...",
|
84 |
+
"本月使用金额": "Использовано средств в этом месяце",
|
85 |
+
"查看[使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)": "[Здесь](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35) можно ознакомиться с инструкцией по использованию",
|
86 |
+
"根据日期时间": "По дате и времени",
|
87 |
+
"模型": "Модель",
|
88 |
+
"模型名称后缀": "Суффикс имени модели",
|
89 |
+
"模型自动总结(消耗tokens)": "Автоматическое подведение итогов модели (потребление токенов)",
|
90 |
+
"模型设置为了:": "Модель настроена на:",
|
91 |
+
"正在尝试更新...": "Попытка обновления...",
|
92 |
+
"添加训练好的模型到模型列表": "Добавить обученную модель в список моделей",
|
93 |
+
"状态": "Статус",
|
94 |
+
"生成内容总结中……": "Создание сводки контента...",
|
95 |
+
"用于定位滥用行为": "Используется для выявления злоупотреблений",
|
96 |
+
"用户名": "Имя пользователя",
|
97 |
+
"由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) 下载最新版脚本": "Разработано [土川虎虎虎](https://space.bilibili.com/29125536), [明昭MZhao](https://space.bilibili.com/24807452) и [Keldos](https://github.com/Keldos-Li).<br />посетите [GitHub Project](https://github.com/GaiZhenbiao/ChuanhuChatGPT) чата Chuanhu, чтобы загрузить последнюю версию скрипта",
|
98 |
+
"知识库": "База знаний",
|
99 |
+
"知识库文件": "Файл базы знаний",
|
100 |
+
"第一条提问": "Первый вопрос",
|
101 |
+
"索引构建完成": "Индексирование завершено.",
|
102 |
+
"网络": "Параметры сети",
|
103 |
+
"获取API使用情况失败:": "Не удалось получитьAPIинформацию об использовании:",
|
104 |
+
"获取IP地理位置失��。原因:": "Не удалось получить географическое положение IP. Причина:",
|
105 |
+
"获取对话时发生错误,请查看后台日志": "Возникла ошибка при получении диалога, пожалуйста, проверьте журналы",
|
106 |
+
"训练": "Обучение",
|
107 |
+
"训练状态": "Статус обучения",
|
108 |
+
"训练轮数(Epochs)": "Количество эпох обучения",
|
109 |
+
"设置": "Настройки",
|
110 |
+
"设置保存文件名": "Установить имя сохраняемого файла",
|
111 |
+
"设置文件名: 默认为.json,可选为.md": "Установить имя файла: по умолчанию .json, можно выбрать .md",
|
112 |
+
"识别公式": "Распознавание формул",
|
113 |
+
"详情": "Подробности",
|
114 |
+
"请查看 config_example.json,配置 Azure OpenAI": "Пожалуйста, просмотрите config_example.json для настройки Azure OpenAI",
|
115 |
+
"请检查网络连接,或者API-Key是否有效。": "Проверьте подключение к сети или действительность API-Key.",
|
116 |
+
"请输入对话内容。": "Пожалуйста, введите содержание диалога.",
|
117 |
+
"请输入有效的文件名,不要包含以下特殊字符:": "Введите действительное имя файла, не содержащее следующих специальных символов: ",
|
118 |
+
"读取超时,无法获取对话。": "Тайм-аут чтения, не удалось получить диалог.",
|
119 |
+
"账单信息不适用": "Информация о счете не применима",
|
120 |
+
"连接超时,无法获取对话。": "Тайм-аут подключения, не удалось получить диалог.",
|
121 |
+
"选择LoRA模型": "Выберите модель LoRA",
|
122 |
+
"选择Prompt模板集合文件": "Выберите файл с набором шаблонов Prompt",
|
123 |
+
"选择回复语言(针对搜索&索引功能)": "Выберите язык ответа (для функций поиска и индексации)",
|
124 |
+
"选择数据集": "Выберите набор данных",
|
125 |
+
"选择模型": "Выберите модель",
|
126 |
+
"重命名该对话": "Переименовать этот диалог",
|
127 |
+
"重新生成": "Пересоздать",
|
128 |
+
"高级": "Расширенные настройки",
|
129 |
+
",本次对话累计消耗了 ": ", Общая стоимость этого диалога составляет ",
|
130 |
+
"💾 保存对话": "💾 Сохранить диалог",
|
131 |
+
"📝 导出为 Markdown": "📝 Экспортировать в Markdown",
|
132 |
+
"🔄 切换API地址": "🔄 Переключить адрес API",
|
133 |
+
"🔄 刷新": "🔄 Обновить",
|
134 |
+
"🔄 检查更新...": "🔄 Проверить обновления...",
|
135 |
+
"🔄 设置代理地址": "🔄 Установить адрес прокси",
|
136 |
+
"🔄 重新生成": "🔄 Пересоздать",
|
137 |
+
"🔙 恢复默认网络设置": "🔙 Восстановить настройки сети по умолчанию",
|
138 |
+
"🗑️ 删除最新对话": "🗑️ Удалить последний диалог",
|
139 |
+
"🗑️ 删除最旧对话": "🗑️ Удалить старейший диалог",
|
140 |
+
"🧹 新的对话": "🧹 Новый диалог"
|
141 |
+
}
|
locale/sv_SE.json
ADDED
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
" 吗?": " ?",
|
3 |
+
"# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ Var försiktig med ändringar. ⚠️",
|
4 |
+
"**发送消息** 或 **提交key** 以显示额度": "**Skicka meddelande** eller **Skicka in nyckel** för att visa kredit",
|
5 |
+
"**本月使用金额** ": "**Månadens användning** ",
|
6 |
+
"**获取API使用情况失败**": "**Misslyckades med att hämta API-användning**",
|
7 |
+
"**获取API使用情况失败**,sensitive_id错误或已过期": "**Misslyckades med att hämta API-användning**, felaktig eller utgången sensitive_id",
|
8 |
+
"**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**Misslyckades med att hämta API-användning**, korrekt sensitive_id behövs i `config.json`",
|
9 |
+
"API key为空,请检查是否输入正确。": "API-nyckeln är tom, kontrollera om den är korrekt inmatad.",
|
10 |
+
"API密钥更改为了": "API-nyckeln har ändrats till",
|
11 |
+
"JSON解析错误,收到的内容: ": "JSON-tolkningsfel, mottaget innehåll: ",
|
12 |
+
"SSL错误,无法获取对话。": "SSL-fel, kunde inte hämta dialogen.",
|
13 |
+
"Token 计数: ": "Tokenräkning: ",
|
14 |
+
"☹️发生了错误:": "☹️Fel: ",
|
15 |
+
"⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "⚠️ För att säkerställa säkerheten för API-nyckeln, vänligen ändra nätverksinställningarna i konfigurationsfilen `config.json`.",
|
16 |
+
"。你仍然可以使用聊天功能。": ". Du kan fortfarande använda chattfunktionen.",
|
17 |
+
"上传": "Ladda upp",
|
18 |
+
"上传了": "Uppladdad",
|
19 |
+
"上传到 OpenAI 后自动填充": "Automatiskt ifylld efter uppladdning till OpenAI",
|
20 |
+
"上传到OpenAI": "Ladda upp till OpenAI",
|
21 |
+
"上传文件": "ladda upp fil",
|
22 |
+
"仅供查看": "Endast för visning",
|
23 |
+
"从Prompt模板中加载": "Ladda från Prompt-mall",
|
24 |
+
"从列表中加载对话": "Ladda dialog från lista",
|
25 |
+
"代理地址": "Proxyadress",
|
26 |
+
"代理错误,无法获取对话。": "Proxyfel, kunde inte hämta dialogen.",
|
27 |
+
"你没有权限访问 GPT4,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)": "Du har inte behörighet att komma åt GPT-4, [läs mer](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)",
|
28 |
+
"你没有选择任何对话历史": "Du har inte valt någon konversationshistorik.",
|
29 |
+
"你真的要删除 ": "Är du säker på att du vill ta bort ",
|
30 |
+
"使用在线搜索": "Använd online-sökning",
|
31 |
+
"停止符,用英文逗号隔开...": "Skriv in stopptecken här, separerade med kommatecken...",
|
32 |
+
"关于": "om",
|
33 |
+
"准备数据集": "Förbered dataset",
|
34 |
+
"切换亮暗色主题": "Byt ljus/mörk tema",
|
35 |
+
"删除对话历史成功": "Raderade konversationens historik.",
|
36 |
+
"删除这轮问答": "Ta bort denna omgång av Q&A",
|
37 |
+
"刷新状态": "Uppdatera status",
|
38 |
+
"剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)": "Återstående kvot är otillräcklig, [läs mer](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%C3%84mnen)",
|
39 |
+
"加载Prompt模板": "Ladda Prompt-mall",
|
40 |
+
"单轮对话": "Enkel dialog",
|
41 |
+
"历史记录(JSON)": "Historikfil (JSON)",
|
42 |
+
"参数": "Parametrar",
|
43 |
+
"双栏pdf": "Två-kolumns pdf",
|
44 |
+
"取消": "Avbryt",
|
45 |
+
"取消所有任务": "Avbryt alla uppgifter",
|
46 |
+
"可选,用于区分不同的模型": "Valfritt, används för att särskilja olika modeller",
|
47 |
+
"启用的工具:": "Aktiverade verktyg: ",
|
48 |
+
"在工具箱中管理知识库文件": "hantera kunskapsbankfiler i verktygslådan",
|
49 |
+
"在线搜索": "onlinesökning",
|
50 |
+
"在这里输入": "Skriv in här",
|
51 |
+
"在这里输入System Prompt...": "Skriv in System Prompt här...",
|
52 |
+
"多账号模式已开启,无需输入key,可直接开始对话": "Flerkontoläge är aktiverat, ingen nyckel behövs, du kan starta dialogen direkt",
|
53 |
+
"好": "OK",
|
54 |
+
"实时传输回答": "Strömmande utdata",
|
55 |
+
"对话": "konversation",
|
56 |
+
"对话历史": "Dialoghistorik",
|
57 |
+
"对话历史记录": "Dialoghistorik",
|
58 |
+
"对话命名方式": "Dialognamn",
|
59 |
+
"导出为 Markdown": "Exportera som Markdown",
|
60 |
+
"川虎Chat": "Chuanhu Chat",
|
61 |
+
"川虎Chat 🚀": "Chuanhu Chat 🚀",
|
62 |
+
"工具箱": "verktygslåda",
|
63 |
+
"已经被删除啦": "Har raderats.",
|
64 |
+
"开始实时传输回答……": "Börjar strömma utdata...",
|
65 |
+
"开始训练": "Börja träning",
|
66 |
+
"微调": "Finjustering",
|
67 |
+
"总结": "Sammanfatta",
|
68 |
+
"总结完成": "Slutfört sammanfattningen.",
|
69 |
+
"您使用的就是最新版!": "Du använder den senaste versionen!",
|
70 |
+
"您的IP区域:": "Din IP-region: ",
|
71 |
+
"您的IP区域:未知。": "Din IP-region: Okänd.",
|
72 |
+
"拓展": "utvidgning",
|
73 |
+
"搜索(支持正则)...": "Sök (stöd för reguljära uttryck)...",
|
74 |
+
"数据集预览": "Datasetförhandsvisning",
|
75 |
+
"文件ID": "Fil-ID",
|
76 |
+
"新���话 ": "Ny dialog ",
|
77 |
+
"新建对话保留Prompt": "Skapa ny konversation med bevarad Prompt",
|
78 |
+
"暂时未知": "Okänd",
|
79 |
+
"更新": "Uppdatera",
|
80 |
+
"更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "Uppdateringen misslyckades, prova att [uppdatera manuellt](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)",
|
81 |
+
"更新成功,请重启本程序": "Uppdaterat framgångsrikt, starta om programmet",
|
82 |
+
"未命名对话历史记录": "Onämnd Dialoghistorik",
|
83 |
+
"未设置代理...": "Inte inställd proxy...",
|
84 |
+
"本月使用金额": "Månadens användning",
|
85 |
+
"查看[使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)": "Se [användarguiden](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35) för mer information",
|
86 |
+
"根据日期时间": "Enligt datum och tid",
|
87 |
+
"模型": "Modell",
|
88 |
+
"模型名称后缀": "Modellnamnstillägg",
|
89 |
+
"模型自动总结(消耗tokens)": "Modellens automatiska sammanfattning (förbrukar tokens)",
|
90 |
+
"模型设置为了:": "Modellen är inställd på: ",
|
91 |
+
"正在尝试更新...": "Försöker uppdatera...",
|
92 |
+
"添加训练好的模型到模型列表": "Lägg till tränad modell i modellistan",
|
93 |
+
"状态": "Status",
|
94 |
+
"生成内容总结中……": "Genererar innehållssammanfattning...",
|
95 |
+
"用于定位滥用行为": "Används för att lokalisera missbruk",
|
96 |
+
"用户名": "Användarnamn",
|
97 |
+
"由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)",
|
98 |
+
"知识库": "kunskapsbank",
|
99 |
+
"知识库文件": "kunskapsbankfil",
|
100 |
+
"第一条提问": "Första frågan",
|
101 |
+
"索引构建完成": "Indexet har blivit byggt färdigt.",
|
102 |
+
"网络": "nätverksparametrar",
|
103 |
+
"获取API使用情况失败:": "Misslyckades med att hämta API-användning:",
|
104 |
+
"获取IP地理位置失败。原因:": "Misslyckades med att hämta IP-plats. Orsak: ",
|
105 |
+
"获取对话时发生错误,请查看后台日志": "Ett fel uppstod när dialogen hämtades, kontrollera bakgrundsloggen",
|
106 |
+
"训练": "träning",
|
107 |
+
"训练状态": "Träningsstatus",
|
108 |
+
"训练轮数(Epochs)": "Träningsomgångar (Epochs)",
|
109 |
+
"设置": "inställningar",
|
110 |
+
"设置保存文件名": "Ställ in sparfilnamn",
|
111 |
+
"设置文件名: 默认为.json,可选为.md": "Ställ in filnamn: standard är .json, valfritt är .md",
|
112 |
+
"识别公式": "Formel OCR",
|
113 |
+
"详情": "Detaljer",
|
114 |
+
"请查看 config_example.json,配置 Azure OpenAI": "Vänligen granska config_example.json för att konfigurera Azure OpenAI",
|
115 |
+
"请检查网络连接,或者API-Key是否有效。": "Kontrollera nätverksanslutningen eller om API-nyckeln är giltig.",
|
116 |
+
"请输入对话内容。": "Ange dialoginnehåll.",
|
117 |
+
"请输入有效的文件名,不要包含以下特殊字符:": "Ange ett giltigt filnamn, använd inte följande specialtecken: ",
|
118 |
+
"读取超时,无法获取对话。": "Läsningen tog för lång tid, kunde inte hämta dialogen.",
|
119 |
+
"账单信息不适用": "Faktureringsinformation är inte tillämplig",
|
120 |
+
"连接超时,无法获取对话。": "Anslutningen tog för lång tid, kunde inte hämta dialogen.",
|
121 |
+
"选择LoRA模型": "Välj LoRA Modell",
|
122 |
+
"选择Prompt模板集合文件": "Välj Prompt-mall Samlingsfil",
|
123 |
+
"选择回复语言(针对搜索&索引功能)": "Välj svarspråk (för sök- och indexfunktion)",
|
124 |
+
"选择数据集": "Välj dataset",
|
125 |
+
"选择模型": "Välj Modell",
|
126 |
+
"重命名该对话": "Byt namn på dialogen",
|
127 |
+
"重新生成": "Återgenerera",
|
128 |
+
"高级": "Avancerat",
|
129 |
+
",本次对话累计消耗了 ": ", Total kostnad för denna dialog är ",
|
130 |
+
"💾 保存对话": "💾 Spara Dialog",
|
131 |
+
"📝 导出为 Markdown": "📝 Exportera som Markdown",
|
132 |
+
"🔄 切换API地址": "🔄 Byt API-adress",
|
133 |
+
"🔄 刷新": "🔄 Uppdatera",
|
134 |
+
"🔄 检查更新...": "🔄 Sök efter uppdateringar...",
|
135 |
+
"🔄 设置代理地址": "🔄 Ställ in Proxyadress",
|
136 |
+
"🔄 重新生成": "🔄 Regenerera",
|
137 |
+
"🔙 恢复默认网络设置": "🔙 Återställ standardnätverksinställningar+",
|
138 |
+
"🗑️ 删除最新对话": "🗑️ Ta bort senaste dialogen",
|
139 |
+
"🗑️ 删除最旧对话": "🗑️ Ta bort äldsta dialogen",
|
140 |
+
"🧹 新的对话": "🧹 Ny Dialog"
|
141 |
+
}
|
locale/vi_VN.json
ADDED
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
" 吗?": " ?",
|
3 |
+
"# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ Lưu ý: Thay đổi yêu cầu cẩn thận. ⚠️",
|
4 |
+
"**发送消息** 或 **提交key** 以显示额度": "**Gửi tin nhắn** hoặc **Gửi khóa(key)** để hiển thị số dư",
|
5 |
+
"**本月使用金额** ": "**Số tiền sử dụng trong tháng** ",
|
6 |
+
"**获取API使用情况失败**": "**Lỗi khi lấy thông tin sử dụng API**",
|
7 |
+
"**获取API使用情况失败**,sensitive_id错误或已过期": "**Lỗi khi lấy thông tin sử dụng API**, sensitive_id sai hoặc đã hết hạn",
|
8 |
+
"**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**Lỗi khi lấy thông tin sử dụng API**, cần điền đúng sensitive_id trong tệp `config.json`",
|
9 |
+
"API key为空,请检查是否输入正确。": "Khóa API trống, vui lòng kiểm tra xem đã nhập đúng chưa.",
|
10 |
+
"API密钥更改为了": "Khóa API đã được thay đổi thành",
|
11 |
+
"JSON解析错误,收到的内容: ": "Lỗi phân tích JSON, nội dung nhận được: ",
|
12 |
+
"SSL错误,无法获取对话。": "Lỗi SSL, không thể nhận cuộc trò chuyện.",
|
13 |
+
"Token 计数: ": "Số lượng Token: ",
|
14 |
+
"☹️发生了错误:": "☹️Lỗi: ",
|
15 |
+
"⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "⚠️ Để đảm bảo an toàn cho API-Key, vui lòng chỉnh sửa cài đặt mạng trong tệp cấu hình `config.json`.",
|
16 |
+
"。你仍然可以使用聊天功能。": ". Bạn vẫn có thể sử dụng chức năng trò chuyện.",
|
17 |
+
"上传": "Tải lên",
|
18 |
+
"上传了": "Tải lên thành công.",
|
19 |
+
"上传到 OpenAI 后自动填充": "Tự động điền sau khi tải lên OpenAI",
|
20 |
+
"上传到OpenAI": "Tải lên OpenAI",
|
21 |
+
"上传文件": "Tải lên tệp",
|
22 |
+
"仅供查看": "Chỉ xem",
|
23 |
+
"从Prompt模板中加载": "Tải từ mẫu Prompt",
|
24 |
+
"从列表中加载对话": "Tải cuộc trò chuyện từ danh sách",
|
25 |
+
"代理地址": "Địa chỉ proxy",
|
26 |
+
"代理错误,无法获取对话。": "Lỗi proxy, không thể nhận cuộc trò chuyện.",
|
27 |
+
"你没有权限访问 GPT4,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)": "Bạn không có quyền truy cập GPT-4, [tìm hiểu thêm](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)",
|
28 |
+
"你没有选择任何对话历史": "Bạn chưa chọn bất kỳ lịch sử trò chuyện nào.",
|
29 |
+
"你真的要删除 ": "Bạn có chắc chắn muốn xóa ",
|
30 |
+
"使用在线搜索": "Sử dụng tìm kiếm trực tuyến",
|
31 |
+
"停止符,用英文逗号隔开...": "Nhập dấu dừng, cách nhau bằng dấu phẩy...",
|
32 |
+
"关于": "Về",
|
33 |
+
"准备数据集": "Chuẩn bị tập dữ liệu",
|
34 |
+
"切换亮暗色主题": "Chuyển đổi chủ đề sáng/tối",
|
35 |
+
"删除对话历史成功": "Xóa lịch sử cuộc trò chuyện thành công.",
|
36 |
+
"删除这轮问答": "Xóa cuộc trò chuyện này",
|
37 |
+
"刷新状态": "Làm mới tình trạng",
|
38 |
+
"剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)": "剩余配额 không đủ, [Nhấn vào đây để biết thêm](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)",
|
39 |
+
"加载Prompt模板": "Tải mẫu Prompt",
|
40 |
+
"单轮对话": "Cuộc trò chuyện một lượt",
|
41 |
+
"历史记录(JSON)": "Tệp lịch sử (JSON)",
|
42 |
+
"参数": "Tham số",
|
43 |
+
"双栏pdf": "PDF hai cột",
|
44 |
+
"取消": "Hủy",
|
45 |
+
"取消所有任务": "Hủy tất cả các nhiệm vụ",
|
46 |
+
"可选,用于区分不同的模型": "Tùy chọn, sử dụng để phân biệt các mô hình khác nhau",
|
47 |
+
"启用的工具:": "Công cụ đã bật: ",
|
48 |
+
"在工具箱中管理知识库文件": "Quản lý tệp cơ sở kiến thức trong hộp công cụ",
|
49 |
+
"在线搜索": "Tìm kiếm trực tuyến",
|
50 |
+
"在这里输入": "Nhập vào đây",
|
51 |
+
"在这里输入System Prompt...": "Nhập System Prompt ở đây...",
|
52 |
+
"多账号模式已开启,无需输入key,可直接开始对话": "Chế độ nhiều tài khoản đã được bật, không cần nhập key, bạn có thể bắt đầu cuộc trò chuyện trực tiếp",
|
53 |
+
"好": "OK",
|
54 |
+
"实时传输回答": "Truyền đầu ra trực tiếp",
|
55 |
+
"对话": "Cuộc trò chuyện",
|
56 |
+
"对话历史": "Lịch sử cuộc trò chuyện",
|
57 |
+
"对话历史记录": "Lịch sử Cuộc trò chuyện",
|
58 |
+
"对话命名方式": "Phương thức đặt tên lịch sử trò chuyện",
|
59 |
+
"导出为 Markdown": "Xuất ra Markdown",
|
60 |
+
"川虎Chat": "Chuanhu Chat",
|
61 |
+
"川虎Chat 🚀": "Chuanhu Chat 🚀",
|
62 |
+
"工具箱": "Hộp công cụ",
|
63 |
+
"已经��删除啦": "Đã bị xóa rồi.",
|
64 |
+
"开始实时传输回答……": "Bắt đầu truyền đầu ra trực tiếp...",
|
65 |
+
"开始训练": "Bắt đầu đào tạo",
|
66 |
+
"微调": "Feeling-tuning",
|
67 |
+
"总结": "Tóm tắt",
|
68 |
+
"总结完成": "Hoàn thành tóm tắt",
|
69 |
+
"您使用的就是最新版!": "Bạn đang sử dụng phiên bản mới nhất!",
|
70 |
+
"您的IP区域:": "Khu vực IP của bạn: ",
|
71 |
+
"您的IP区域:未知。": "Khu vực IP của bạn: Không xác định.",
|
72 |
+
"拓展": "Mở rộng",
|
73 |
+
"搜索(支持正则)...": "Tìm kiếm (hỗ trợ regex)...",
|
74 |
+
"数据集预览": "Xem trước tập dữ liệu",
|
75 |
+
"文件ID": "ID Tệp",
|
76 |
+
"新对话 ": "Cuộc trò chuyện mới ",
|
77 |
+
"新建对话保留Prompt": "Tạo Cuộc trò chuyện mới và giữ Prompt nguyên vẹn",
|
78 |
+
"暂时未知": "Tạm thời chưa xác định",
|
79 |
+
"更新": "Cập nhật",
|
80 |
+
"更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "Cập nhật thất bại, vui lòng thử [cập nhật thủ công](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)",
|
81 |
+
"更新成功,请重启本程序": "Cập nhật thành công, vui lòng khởi động lại chương trình này",
|
82 |
+
"未命名对话历史记录": "Lịch sử Cuộc trò chuyện không đặt tên",
|
83 |
+
"未设置代理...": "Không có proxy...",
|
84 |
+
"本月使用金额": "Số tiền sử dụng trong tháng",
|
85 |
+
"查看[使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35)": "Xem [hướng dẫn sử dụng](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#微调-gpt-35) để biết thêm chi tiết",
|
86 |
+
"根据日期时间": "Theo ngày và giờ",
|
87 |
+
"模型": "Mô hình",
|
88 |
+
"模型名称后缀": "Hậu tố Tên Mô hình",
|
89 |
+
"模型自动总结(消耗tokens)": "Tự động tóm tắt bằng LLM (Tiêu thụ token)",
|
90 |
+
"模型设置为了:": "Mô hình đã được đặt thành: ",
|
91 |
+
"正在尝试更新...": "Đang cố gắng cập nhật...",
|
92 |
+
"添加训练好的模型到模型列表": "Thêm mô hình đã đào tạo vào danh sách mô hình",
|
93 |
+
"状态": "Tình trạng",
|
94 |
+
"生成内容总结中……": "Đang tạo tóm tắt nội dung...",
|
95 |
+
"用于定位滥用行为": "Sử dụng để xác định hành vi lạm dụng",
|
96 |
+
"用户名": "Tên người dùng",
|
97 |
+
"由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) 下载最新版脚本": "Phát triển bởi Bilibili [土川虎虎虎](https://space.bilibili.com/29125536), [明昭MZhao](https://space.bilibili.com/24807452) và [Keldos](https://github.com/Keldos-Li)\n\nTải mã nguồn mới nhất từ [GitHub](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
|
98 |
+
"知识库": "Cơ sở kiến thức",
|
99 |
+
"知识库文件": "Tệp cơ sở kiến thức",
|
100 |
+
"第一条提问": "Theo câu hỏi đầu tiên",
|
101 |
+
"索引构建完成": "Xây dựng chỉ mục hoàn tất",
|
102 |
+
"网络": "Mạng",
|
103 |
+
"获取API使用情况失败:": "Lỗi khi lấy thông tin sử dụng API:",
|
104 |
+
"获取IP地理位置失败。原因:": "Không thể lấy vị trí địa lý của IP. Nguyên nhân: ",
|
105 |
+
"获取对话时发生错误,请查看后台日志": "Xảy ra lỗi khi nhận cuộc trò chuyện, kiểm tra nhật ký nền",
|
106 |
+
"训练": "Đào tạo",
|
107 |
+
"训练状态": "Tình trạng đào tạo",
|
108 |
+
"训练轮数(Epochs)": "Số lượt đào tạo (Epochs)",
|
109 |
+
"设置": "Cài đặt",
|
110 |
+
"设置保存文件名": "Đặt tên tệp lưu",
|
111 |
+
"设置文件名: 默认为.json,可选为.md": "Đặt tên tệp: mặc định là .json, tùy chọn là .md",
|
112 |
+
"识别公式": "Nhận dạng công thức",
|
113 |
+
"详情": "Chi tiết",
|
114 |
+
"请查看 config_example.json,配置 Azure OpenAI": "Vui lòng xem tệp config_example.json để cấu hình Azure OpenAI",
|
115 |
+
"请检查网络连接,或者API-Key是否有效。": "Vui lòng kiểm tra kết nối mạng hoặc xem xét tính hợp lệ của API-Key.",
|
116 |
+
"请输入对话内容。": "Nhập nội dung cuộc trò chuyện.",
|
117 |
+
"请输入有效的文件名,不要包含以下特殊字符:": "Vui lòng nhập tên tệp hợp lệ, không chứa các ký tự đặc biệt sau: ",
|
118 |
+
"读取超时,无法获取对话。": "Hết thời gian đọc, không thể nhận cuộc trò chuyện.",
|
119 |
+
"账单信息不适用": "Thông tin thanh toán không áp dụng",
|
120 |
+
"连接超时,无法获取对话。": "Hết thời gian kết nối, không thể nhận cuộc trò chuyện.",
|
121 |
+
"选择LoRA模型": "Chọn Mô hình LoRA",
|
122 |
+
"选择Prompt模板集合文件": "Chọn Tệp bộ sưu tập mẫu Prompt",
|
123 |
+
"选择回复语言��针对搜索&索引功能)": "Chọn ngôn ngữ phản hồi (đối với chức năng tìm kiếm & chỉ mục)",
|
124 |
+
"选择数据集": "Chọn tập dữ liệu",
|
125 |
+
"选择模型": "Chọn Mô hình",
|
126 |
+
"重命名该对话": "Đổi tên cuộc trò chuyện này",
|
127 |
+
"重新生成": "Tạo lại",
|
128 |
+
"高级": "Nâng cao",
|
129 |
+
",本次对话累计消耗了 ": ", Tổng cộng chi phí cho cuộc trò chuyện này là ",
|
130 |
+
"💾 保存对话": "💾 Lưu Cuộc trò chuyện",
|
131 |
+
"📝 导出为 Markdown": "📝 Xuất ra dưới dạng Markdown",
|
132 |
+
"🔄 切换API地址": "🔄 Chuyển đổi Địa chỉ API",
|
133 |
+
"🔄 刷新": "🔄 Làm mới",
|
134 |
+
"🔄 检查更新...": "🔄 Kiểm tra cập nhật...",
|
135 |
+
"🔄 设置代理地址": "🔄 Đặt Địa chỉ Proxy",
|
136 |
+
"🔄 重新生成": "🔄 Tạo lại",
|
137 |
+
"🔙 恢复默认网络设置": "🔙 Khôi phục cài đặt mạng mặc định",
|
138 |
+
"🗑️ 删除最新对话": "🗑️ Xóa cuộc trò chuyện mới nhất",
|
139 |
+
"🗑️ 删除最旧对话": "🗑️ Xóa cuộc trò chuyện cũ nhất",
|
140 |
+
"🧹 新的对话": "🧹 Cuộc trò chuyện mới"
|
141 |
+
}
|
locale/zh_CN.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{}
|
modules/config.py
CHANGED
@@ -27,7 +27,8 @@ __all__ = [
|
|
27 |
"latex_delimiters_set",
|
28 |
"hide_history_when_not_logged_in",
|
29 |
"default_chuanhu_assistant_model",
|
30 |
-
"show_api_billing"
|
|
|
31 |
]
|
32 |
|
33 |
# 添加一个统一的config文件,避免文件过多造成的疑惑(优先级最低)
|
@@ -45,15 +46,12 @@ def load_config_to_environ(key_list):
|
|
45 |
if key in config:
|
46 |
os.environ[key.upper()] = os.environ.get(key.upper(), config[key])
|
47 |
|
48 |
-
|
49 |
-
lang_config = config.get("language", "auto")
|
50 |
-
language = os.environ.get("LANGUAGE", lang_config)
|
51 |
-
|
52 |
hide_history_when_not_logged_in = config.get(
|
53 |
"hide_history_when_not_logged_in", False)
|
54 |
check_update = config.get("check_update", True)
|
55 |
show_api_billing = config.get("show_api_billing", False)
|
56 |
show_api_billing = bool(os.environ.get("SHOW_API_BILLING", show_api_billing))
|
|
|
57 |
|
58 |
if os.path.exists("api_key.txt"):
|
59 |
logging.info("检测到api_key.txt文件,正在进行迁移...")
|
@@ -96,6 +94,10 @@ else:
|
|
96 |
sensitive_id = config.get("sensitive_id", "")
|
97 |
sensitive_id = os.environ.get("SENSITIVE_ID", sensitive_id)
|
98 |
|
|
|
|
|
|
|
|
|
99 |
# 模型配置
|
100 |
if "extra_models" in config:
|
101 |
presets.MODELS.extend(config["extra_models"])
|
@@ -123,6 +125,16 @@ os.environ["MIDJOURNEY_DISCORD_PROXY_URL"] = midjourney_discord_proxy_url
|
|
123 |
midjourney_temp_folder = config.get("midjourney_temp_folder", "")
|
124 |
os.environ["MIDJOURNEY_TEMP_FOLDER"] = midjourney_temp_folder
|
125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
load_config_to_environ(["openai_api_type", "azure_openai_api_key", "azure_openai_api_base_url",
|
127 |
"azure_openai_api_version", "azure_deployment_name", "azure_embedding_deployment_name", "azure_embedding_model_name"])
|
128 |
|
@@ -277,4 +289,12 @@ share = config.get("share", False)
|
|
277 |
|
278 |
# avatar
|
279 |
bot_avatar = config.get("bot_avatar", "default")
|
280 |
-
user_avatar = config.get("user_avatar", "default")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
"latex_delimiters_set",
|
28 |
"hide_history_when_not_logged_in",
|
29 |
"default_chuanhu_assistant_model",
|
30 |
+
"show_api_billing",
|
31 |
+
"chat_name_method_index",
|
32 |
]
|
33 |
|
34 |
# 添加一个统一的config文件,避免文件过多造成的疑惑(优先级最低)
|
|
|
46 |
if key in config:
|
47 |
os.environ[key.upper()] = os.environ.get(key.upper(), config[key])
|
48 |
|
|
|
|
|
|
|
|
|
49 |
hide_history_when_not_logged_in = config.get(
|
50 |
"hide_history_when_not_logged_in", False)
|
51 |
check_update = config.get("check_update", True)
|
52 |
show_api_billing = config.get("show_api_billing", False)
|
53 |
show_api_billing = bool(os.environ.get("SHOW_API_BILLING", show_api_billing))
|
54 |
+
chat_name_method_index = config.get("chat_name_method_index", 2)
|
55 |
|
56 |
if os.path.exists("api_key.txt"):
|
57 |
logging.info("检测到api_key.txt文件,正在进行迁移...")
|
|
|
94 |
sensitive_id = config.get("sensitive_id", "")
|
95 |
sensitive_id = os.environ.get("SENSITIVE_ID", sensitive_id)
|
96 |
|
97 |
+
if "available_models" in config:
|
98 |
+
presets.MODELS = config["available_models"]
|
99 |
+
logging.info(f"已设置可用模型:{config['available_models']}")
|
100 |
+
|
101 |
# 模型配置
|
102 |
if "extra_models" in config:
|
103 |
presets.MODELS.extend(config["extra_models"])
|
|
|
125 |
midjourney_temp_folder = config.get("midjourney_temp_folder", "")
|
126 |
os.environ["MIDJOURNEY_TEMP_FOLDER"] = midjourney_temp_folder
|
127 |
|
128 |
+
spark_api_key = config.get("spark_api_key", "")
|
129 |
+
os.environ["SPARK_API_KEY"] = spark_api_key
|
130 |
+
spark_appid = config.get("spark_appid", "")
|
131 |
+
os.environ["SPARK_APPID"] = spark_appid
|
132 |
+
spark_api_secret = config.get("spark_api_secret", "")
|
133 |
+
os.environ["SPARK_API_SECRET"] = spark_api_secret
|
134 |
+
|
135 |
+
claude_api_secret = config.get("claude_api_secret", "")
|
136 |
+
os.environ["CLAUDE_API_SECRET"] = claude_api_secret
|
137 |
+
|
138 |
load_config_to_environ(["openai_api_type", "azure_openai_api_key", "azure_openai_api_base_url",
|
139 |
"azure_openai_api_version", "azure_deployment_name", "azure_embedding_deployment_name", "azure_embedding_model_name"])
|
140 |
|
|
|
289 |
|
290 |
# avatar
|
291 |
bot_avatar = config.get("bot_avatar", "default")
|
292 |
+
user_avatar = config.get("user_avatar", "default")
|
293 |
+
if bot_avatar == "" or bot_avatar == "none" or bot_avatar is None:
|
294 |
+
bot_avatar = None
|
295 |
+
elif bot_avatar == "default":
|
296 |
+
bot_avatar = "web_assets/chatbot.png"
|
297 |
+
if user_avatar == "" or user_avatar == "none" or user_avatar is None:
|
298 |
+
user_avatar = None
|
299 |
+
elif user_avatar == "default":
|
300 |
+
user_avatar = "web_assets/user.png"
|
modules/index_func.py
CHANGED
@@ -23,6 +23,7 @@ def get_documents(file_src):
|
|
23 |
filename = os.path.basename(filepath)
|
24 |
file_type = os.path.splitext(filename)[1]
|
25 |
logging.info(f"loading file: {filename}")
|
|
|
26 |
try:
|
27 |
if file_type == ".pdf":
|
28 |
logging.debug("Loading PDF...")
|
@@ -72,8 +73,9 @@ def get_documents(file_src):
|
|
72 |
logging.error(f"Error loading file: {filename}")
|
73 |
traceback.print_exc()
|
74 |
|
75 |
-
texts
|
76 |
-
|
|
|
77 |
logging.debug("Documents loaded.")
|
78 |
return documents
|
79 |
|
@@ -87,6 +89,7 @@ def construct_index(
|
|
87 |
chunk_size_limit=600,
|
88 |
embedding_limit=None,
|
89 |
separator=" ",
|
|
|
90 |
):
|
91 |
from langchain.chat_models import ChatOpenAI
|
92 |
from langchain.vectorstores import FAISS
|
@@ -114,7 +117,7 @@ def construct_index(
|
|
114 |
else:
|
115 |
embeddings = OpenAIEmbeddings(deployment=os.environ["AZURE_EMBEDDING_DEPLOYMENT_NAME"], openai_api_key=os.environ["AZURE_OPENAI_API_KEY"],
|
116 |
model=os.environ["AZURE_EMBEDDING_MODEL_NAME"], openai_api_base=os.environ["AZURE_OPENAI_API_BASE_URL"], openai_api_type="azure")
|
117 |
-
if os.path.exists(index_path):
|
118 |
logging.info("找到了缓存的索引文件,加载中……")
|
119 |
return FAISS.load_local(index_path, embeddings)
|
120 |
else:
|
|
|
23 |
filename = os.path.basename(filepath)
|
24 |
file_type = os.path.splitext(filename)[1]
|
25 |
logging.info(f"loading file: {filename}")
|
26 |
+
texts = None
|
27 |
try:
|
28 |
if file_type == ".pdf":
|
29 |
logging.debug("Loading PDF...")
|
|
|
73 |
logging.error(f"Error loading file: {filename}")
|
74 |
traceback.print_exc()
|
75 |
|
76 |
+
if texts is not None:
|
77 |
+
texts = text_splitter.split_documents(texts)
|
78 |
+
documents.extend(texts)
|
79 |
logging.debug("Documents loaded.")
|
80 |
return documents
|
81 |
|
|
|
89 |
chunk_size_limit=600,
|
90 |
embedding_limit=None,
|
91 |
separator=" ",
|
92 |
+
load_from_cache_if_possible=True,
|
93 |
):
|
94 |
from langchain.chat_models import ChatOpenAI
|
95 |
from langchain.vectorstores import FAISS
|
|
|
117 |
else:
|
118 |
embeddings = OpenAIEmbeddings(deployment=os.environ["AZURE_EMBEDDING_DEPLOYMENT_NAME"], openai_api_key=os.environ["AZURE_OPENAI_API_KEY"],
|
119 |
model=os.environ["AZURE_EMBEDDING_MODEL_NAME"], openai_api_base=os.environ["AZURE_OPENAI_API_BASE_URL"], openai_api_type="azure")
|
120 |
+
if os.path.exists(index_path) and load_from_cache_if_possible:
|
121 |
logging.info("找到了缓存的索引文件,加载中……")
|
122 |
return FAISS.load_local(index_path, embeddings)
|
123 |
else:
|
modules/models/Azure.py
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from langchain.chat_models import AzureChatOpenAI, ChatOpenAI
|
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 |
+
streaming=True
|
18 |
+
)
|
modules/models/ChatGLM.py
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import logging
|
4 |
+
import os
|
5 |
+
import platform
|
6 |
+
|
7 |
+
import colorama
|
8 |
+
|
9 |
+
from ..index_func import *
|
10 |
+
from ..presets import *
|
11 |
+
from ..utils import *
|
12 |
+
from .base_model import BaseLLMModel
|
13 |
+
|
14 |
+
|
15 |
+
class ChatGLM_Client(BaseLLMModel):
|
16 |
+
def __init__(self, model_name, user_name="") -> None:
|
17 |
+
super().__init__(model_name=model_name, user=user_name)
|
18 |
+
import torch
|
19 |
+
from transformers import AutoModel, AutoTokenizer
|
20 |
+
global CHATGLM_TOKENIZER, CHATGLM_MODEL
|
21 |
+
if CHATGLM_TOKENIZER is None or CHATGLM_MODEL is None:
|
22 |
+
system_name = platform.system()
|
23 |
+
model_path = None
|
24 |
+
if os.path.exists("models"):
|
25 |
+
model_dirs = os.listdir("models")
|
26 |
+
if model_name in model_dirs:
|
27 |
+
model_path = f"models/{model_name}"
|
28 |
+
if model_path is not None:
|
29 |
+
model_source = model_path
|
30 |
+
else:
|
31 |
+
model_source = f"THUDM/{model_name}"
|
32 |
+
CHATGLM_TOKENIZER = AutoTokenizer.from_pretrained(
|
33 |
+
model_source, trust_remote_code=True
|
34 |
+
)
|
35 |
+
quantified = False
|
36 |
+
if "int4" in model_name:
|
37 |
+
quantified = True
|
38 |
+
model = AutoModel.from_pretrained(
|
39 |
+
model_source, trust_remote_code=True
|
40 |
+
)
|
41 |
+
if torch.cuda.is_available():
|
42 |
+
# run on CUDA
|
43 |
+
logging.info("CUDA is available, using CUDA")
|
44 |
+
model = model.half().cuda()
|
45 |
+
# mps加速还存在一些问题,暂时不使用
|
46 |
+
elif system_name == "Darwin" and model_path is not None and not quantified:
|
47 |
+
logging.info("Running on macOS, using MPS")
|
48 |
+
# running on macOS and model already downloaded
|
49 |
+
model = model.half().to("mps")
|
50 |
+
else:
|
51 |
+
logging.info("GPU is not available, using CPU")
|
52 |
+
model = model.float()
|
53 |
+
model = model.eval()
|
54 |
+
CHATGLM_MODEL = model
|
55 |
+
|
56 |
+
def _get_glm_style_input(self):
|
57 |
+
history = [x["content"] for x in self.history]
|
58 |
+
query = history.pop()
|
59 |
+
logging.debug(colorama.Fore.YELLOW +
|
60 |
+
f"{history}" + colorama.Fore.RESET)
|
61 |
+
assert (
|
62 |
+
len(history) % 2 == 0
|
63 |
+
), f"History should be even length. current history is: {history}"
|
64 |
+
history = [[history[i], history[i + 1]]
|
65 |
+
for i in range(0, len(history), 2)]
|
66 |
+
return history, query
|
67 |
+
|
68 |
+
def get_answer_at_once(self):
|
69 |
+
history, query = self._get_glm_style_input()
|
70 |
+
response, _ = CHATGLM_MODEL.chat(
|
71 |
+
CHATGLM_TOKENIZER, query, history=history)
|
72 |
+
return response, len(response)
|
73 |
+
|
74 |
+
def get_answer_stream_iter(self):
|
75 |
+
history, query = self._get_glm_style_input()
|
76 |
+
for response, history in CHATGLM_MODEL.stream_chat(
|
77 |
+
CHATGLM_TOKENIZER,
|
78 |
+
query,
|
79 |
+
history,
|
80 |
+
max_length=self.token_upper_limit,
|
81 |
+
top_p=self.top_p,
|
82 |
+
temperature=self.temperature,
|
83 |
+
):
|
84 |
+
yield response
|
modules/models/ChuanhuAgent.py
CHANGED
@@ -63,7 +63,23 @@ class ChuanhuAgent_Client(BaseLLMModel):
|
|
63 |
self.index_summary = None
|
64 |
self.index = None
|
65 |
if "Pro" in self.model_name:
|
66 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
else:
|
68 |
self.tools = load_tools(["ddg-search", "llm-math", "arxiv", "wikipedia"], llm=self.llm)
|
69 |
self.tools.append(
|
@@ -96,7 +112,7 @@ class ChuanhuAgent_Client(BaseLLMModel):
|
|
96 |
def google_search_simple(self, query):
|
97 |
results = []
|
98 |
with DDGS() as ddgs:
|
99 |
-
ddgs_gen = ddgs.text(
|
100 |
for r in islice(ddgs_gen, 10):
|
101 |
results.append({
|
102 |
"title": r["title"],
|
|
|
63 |
self.index_summary = None
|
64 |
self.index = None
|
65 |
if "Pro" in self.model_name:
|
66 |
+
tools_to_enable = ["llm-math", "arxiv", "wikipedia"]
|
67 |
+
# if exists GOOGLE_CSE_ID and GOOGLE_API_KEY, enable google-search-results-json
|
68 |
+
if os.environ.get("GOOGLE_CSE_ID", None) is not None and os.environ.get("GOOGLE_API_KEY", None) is not None:
|
69 |
+
tools_to_enable.append("google-search-results-json")
|
70 |
+
else:
|
71 |
+
logging.warning("GOOGLE_CSE_ID and/or GOOGLE_API_KEY not found, google-search-results-json is disabled.")
|
72 |
+
# if exists WOLFRAM_ALPHA_APPID, enable wolfram-alpha
|
73 |
+
if os.environ.get("WOLFRAM_ALPHA_APPID", None) is not None:
|
74 |
+
tools_to_enable.append("wolfram-alpha")
|
75 |
+
else:
|
76 |
+
logging.warning("WOLFRAM_ALPHA_APPID not found, wolfram-alpha is disabled.")
|
77 |
+
# if exists SERPAPI_API_KEY, enable serpapi
|
78 |
+
if os.environ.get("SERPAPI_API_KEY", None) is not None:
|
79 |
+
tools_to_enable.append("serpapi")
|
80 |
+
else:
|
81 |
+
logging.warning("SERPAPI_API_KEY not found, serpapi is disabled.")
|
82 |
+
self.tools = load_tools(tools_to_enable, llm=self.llm)
|
83 |
else:
|
84 |
self.tools = load_tools(["ddg-search", "llm-math", "arxiv", "wikipedia"], llm=self.llm)
|
85 |
self.tools.append(
|
|
|
112 |
def google_search_simple(self, query):
|
113 |
results = []
|
114 |
with DDGS() as ddgs:
|
115 |
+
ddgs_gen = ddgs.text(query, backend="lite")
|
116 |
for r in islice(ddgs_gen, 10):
|
117 |
results.append({
|
118 |
"title": r["title"],
|
modules/models/Claude.py
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
from anthropic import Anthropic, HUMAN_PROMPT, AI_PROMPT
|
3 |
+
from ..presets import *
|
4 |
+
from ..utils import *
|
5 |
+
|
6 |
+
from .base_model import BaseLLMModel
|
7 |
+
|
8 |
+
|
9 |
+
class Claude_Client(BaseLLMModel):
|
10 |
+
def __init__(self, model_name, api_secret) -> None:
|
11 |
+
super().__init__(model_name=model_name)
|
12 |
+
self.api_secret = api_secret
|
13 |
+
if None in [self.api_secret]:
|
14 |
+
raise Exception("请在配置文件或者环境变量中设置Claude的API Secret")
|
15 |
+
self.claude_client = Anthropic(api_key=self.api_secret)
|
16 |
+
|
17 |
+
|
18 |
+
def get_answer_stream_iter(self):
|
19 |
+
system_prompt = self.system_prompt
|
20 |
+
history = self.history
|
21 |
+
if system_prompt is not None:
|
22 |
+
history = [construct_system(system_prompt), *history]
|
23 |
+
|
24 |
+
completion = self.claude_client.completions.create(
|
25 |
+
model=self.model_name,
|
26 |
+
max_tokens_to_sample=300,
|
27 |
+
prompt=f"{HUMAN_PROMPT}{history}{AI_PROMPT}",
|
28 |
+
stream=True,
|
29 |
+
)
|
30 |
+
if completion is not None:
|
31 |
+
partial_text = ""
|
32 |
+
for chunk in completion:
|
33 |
+
partial_text += chunk.completion
|
34 |
+
yield partial_text
|
35 |
+
else:
|
36 |
+
yield STANDARD_ERROR_MSG + GENERAL_ERROR_MSG
|
37 |
+
|
38 |
+
|
39 |
+
def get_answer_at_once(self):
|
40 |
+
system_prompt = self.system_prompt
|
41 |
+
history = self.history
|
42 |
+
if system_prompt is not None:
|
43 |
+
history = [construct_system(system_prompt), *history]
|
44 |
+
|
45 |
+
completion = self.claude_client.completions.create(
|
46 |
+
model=self.model_name,
|
47 |
+
max_tokens_to_sample=300,
|
48 |
+
prompt=f"{HUMAN_PROMPT}{history}{AI_PROMPT}",
|
49 |
+
)
|
50 |
+
if completion is not None:
|
51 |
+
return completion.completion, len(completion.completion)
|
52 |
+
else:
|
53 |
+
return "获取资源错误", 0
|
54 |
+
|
55 |
+
|
modules/models/GooglePaLM.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from .base_model import BaseLLMModel
|
2 |
+
import google.generativeai as palm
|
3 |
+
|
4 |
+
|
5 |
+
class Google_PaLM_Client(BaseLLMModel):
|
6 |
+
def __init__(self, model_name, api_key, user_name="") -> None:
|
7 |
+
super().__init__(model_name=model_name, user=user_name)
|
8 |
+
self.api_key = api_key
|
9 |
+
|
10 |
+
def _get_palm_style_input(self):
|
11 |
+
new_history = []
|
12 |
+
for item in self.history:
|
13 |
+
if item["role"] == "user":
|
14 |
+
new_history.append({'author': '1', 'content': item["content"]})
|
15 |
+
else:
|
16 |
+
new_history.append({'author': '0', 'content': item["content"]})
|
17 |
+
return new_history
|
18 |
+
|
19 |
+
def get_answer_at_once(self):
|
20 |
+
palm.configure(api_key=self.api_key)
|
21 |
+
messages = self._get_palm_style_input()
|
22 |
+
response = palm.chat(context=self.system_prompt, messages=messages,
|
23 |
+
temperature=self.temperature, top_p=self.top_p)
|
24 |
+
if response.last is not None:
|
25 |
+
return response.last, len(response.last)
|
26 |
+
else:
|
27 |
+
reasons = '\n\n'.join(
|
28 |
+
reason['reason'].name for reason in response.filters)
|
29 |
+
return "由于下面的原因,Google 拒绝返回 PaLM 的回答:\n\n" + reasons, 0
|
modules/models/LLaMA.py
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import json
|
4 |
+
import os
|
5 |
+
|
6 |
+
from huggingface_hub import hf_hub_download
|
7 |
+
from llama_cpp import Llama
|
8 |
+
|
9 |
+
from ..index_func import *
|
10 |
+
from ..presets import *
|
11 |
+
from ..utils import *
|
12 |
+
from .base_model import BaseLLMModel
|
13 |
+
|
14 |
+
SYS_PREFIX = "<<SYS>>\n"
|
15 |
+
SYS_POSTFIX = "\n<</SYS>>\n\n"
|
16 |
+
INST_PREFIX = "<s>[INST] "
|
17 |
+
INST_POSTFIX = " "
|
18 |
+
OUTPUT_PREFIX = "[/INST] "
|
19 |
+
OUTPUT_POSTFIX = "</s>"
|
20 |
+
|
21 |
+
|
22 |
+
def download(repo_id, filename, retry=10):
|
23 |
+
if os.path.exists("./models/downloaded_models.json"):
|
24 |
+
with open("./models/downloaded_models.json", "r") as f:
|
25 |
+
downloaded_models = json.load(f)
|
26 |
+
if repo_id in downloaded_models:
|
27 |
+
return downloaded_models[repo_id]["path"]
|
28 |
+
else:
|
29 |
+
downloaded_models = {}
|
30 |
+
while retry > 0:
|
31 |
+
try:
|
32 |
+
model_path = hf_hub_download(
|
33 |
+
repo_id=repo_id,
|
34 |
+
filename=filename,
|
35 |
+
cache_dir="models",
|
36 |
+
resume_download=True,
|
37 |
+
)
|
38 |
+
downloaded_models[repo_id] = {"path": model_path}
|
39 |
+
with open("./models/downloaded_models.json", "w") as f:
|
40 |
+
json.dump(downloaded_models, f)
|
41 |
+
break
|
42 |
+
except:
|
43 |
+
print("Error downloading model, retrying...")
|
44 |
+
retry -= 1
|
45 |
+
if retry == 0:
|
46 |
+
raise Exception("Error downloading model, please try again later.")
|
47 |
+
return model_path
|
48 |
+
|
49 |
+
|
50 |
+
class LLaMA_Client(BaseLLMModel):
|
51 |
+
def __init__(self, model_name, lora_path=None, user_name="") -> None:
|
52 |
+
super().__init__(model_name=model_name, user=user_name)
|
53 |
+
|
54 |
+
self.max_generation_token = 1000
|
55 |
+
if model_name in MODEL_METADATA:
|
56 |
+
path_to_model = download(
|
57 |
+
MODEL_METADATA[model_name]["repo_id"],
|
58 |
+
MODEL_METADATA[model_name]["filelist"][0],
|
59 |
+
)
|
60 |
+
else:
|
61 |
+
dir_to_model = os.path.join("models", model_name)
|
62 |
+
# look for nay .gguf file in the dir_to_model directory and its subdirectories
|
63 |
+
path_to_model = None
|
64 |
+
for root, dirs, files in os.walk(dir_to_model):
|
65 |
+
for file in files:
|
66 |
+
if file.endswith(".gguf"):
|
67 |
+
path_to_model = os.path.join(root, file)
|
68 |
+
break
|
69 |
+
if path_to_model is not None:
|
70 |
+
break
|
71 |
+
self.system_prompt = ""
|
72 |
+
|
73 |
+
if lora_path is not None:
|
74 |
+
lora_path = os.path.join("lora", lora_path)
|
75 |
+
self.model = Llama(model_path=path_to_model, lora_path=lora_path)
|
76 |
+
else:
|
77 |
+
self.model = Llama(model_path=path_to_model)
|
78 |
+
|
79 |
+
def _get_llama_style_input(self):
|
80 |
+
context = []
|
81 |
+
for conv in self.history:
|
82 |
+
if conv["role"] == "system":
|
83 |
+
context.append(SYS_PREFIX + conv["content"] + SYS_POSTFIX)
|
84 |
+
elif conv["role"] == "user":
|
85 |
+
context.append(
|
86 |
+
INST_PREFIX + conv["content"] + INST_POSTFIX + OUTPUT_PREFIX
|
87 |
+
)
|
88 |
+
else:
|
89 |
+
context.append(conv["content"] + OUTPUT_POSTFIX)
|
90 |
+
return "".join(context)
|
91 |
+
# for conv in self.history:
|
92 |
+
# if conv["role"] == "system":
|
93 |
+
# context.append(conv["content"])
|
94 |
+
# elif conv["role"] == "user":
|
95 |
+
# context.append(
|
96 |
+
# conv["content"]
|
97 |
+
# )
|
98 |
+
# else:
|
99 |
+
# context.append(conv["content"])
|
100 |
+
# return "\n\n".join(context)+"\n\n"
|
101 |
+
|
102 |
+
def get_answer_at_once(self):
|
103 |
+
context = self._get_llama_style_input()
|
104 |
+
response = self.model(
|
105 |
+
context,
|
106 |
+
max_tokens=self.max_generation_token,
|
107 |
+
stop=[],
|
108 |
+
echo=False,
|
109 |
+
stream=False,
|
110 |
+
)
|
111 |
+
return response, len(response)
|
112 |
+
|
113 |
+
def get_answer_stream_iter(self):
|
114 |
+
context = self._get_llama_style_input()
|
115 |
+
iter = self.model(
|
116 |
+
context,
|
117 |
+
max_tokens=self.max_generation_token,
|
118 |
+
stop=[SYS_PREFIX, SYS_POSTFIX, INST_PREFIX, OUTPUT_PREFIX,OUTPUT_POSTFIX],
|
119 |
+
echo=False,
|
120 |
+
stream=True,
|
121 |
+
)
|
122 |
+
partial_text = ""
|
123 |
+
for i in iter:
|
124 |
+
response = i["choices"][0]["text"]
|
125 |
+
partial_text += response
|
126 |
+
yield partial_text
|
modules/models/OpenAI.py
ADDED
@@ -0,0 +1,279 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import json
|
4 |
+
import logging
|
5 |
+
import traceback
|
6 |
+
|
7 |
+
import colorama
|
8 |
+
import requests
|
9 |
+
|
10 |
+
from .. import shared
|
11 |
+
from ..config import retrieve_proxy, sensitive_id, usage_limit
|
12 |
+
from ..index_func import *
|
13 |
+
from ..presets import *
|
14 |
+
from ..utils import *
|
15 |
+
from .base_model import BaseLLMModel
|
16 |
+
|
17 |
+
|
18 |
+
class OpenAIClient(BaseLLMModel):
|
19 |
+
def __init__(
|
20 |
+
self,
|
21 |
+
model_name,
|
22 |
+
api_key,
|
23 |
+
system_prompt=INITIAL_SYSTEM_PROMPT,
|
24 |
+
temperature=1.0,
|
25 |
+
top_p=1.0,
|
26 |
+
user_name=""
|
27 |
+
) -> None:
|
28 |
+
super().__init__(
|
29 |
+
model_name=MODEL_METADATA[model_name]["model_name"],
|
30 |
+
temperature=temperature,
|
31 |
+
top_p=top_p,
|
32 |
+
system_prompt=system_prompt,
|
33 |
+
user=user_name
|
34 |
+
)
|
35 |
+
self.api_key = api_key
|
36 |
+
self.need_api_key = True
|
37 |
+
self._refresh_header()
|
38 |
+
|
39 |
+
def get_answer_stream_iter(self):
|
40 |
+
response = self._get_response(stream=True)
|
41 |
+
if response is not None:
|
42 |
+
iter = self._decode_chat_response(response)
|
43 |
+
partial_text = ""
|
44 |
+
for i in iter:
|
45 |
+
partial_text += i
|
46 |
+
yield partial_text
|
47 |
+
else:
|
48 |
+
yield STANDARD_ERROR_MSG + GENERAL_ERROR_MSG
|
49 |
+
|
50 |
+
def get_answer_at_once(self):
|
51 |
+
response = self._get_response()
|
52 |
+
response = json.loads(response.text)
|
53 |
+
content = response["choices"][0]["message"]["content"]
|
54 |
+
total_token_count = response["usage"]["total_tokens"]
|
55 |
+
return content, total_token_count
|
56 |
+
|
57 |
+
def count_token(self, user_input):
|
58 |
+
input_token_count = count_token(construct_user(user_input))
|
59 |
+
if self.system_prompt is not None and len(self.all_token_counts) == 0:
|
60 |
+
system_prompt_token_count = count_token(
|
61 |
+
construct_system(self.system_prompt)
|
62 |
+
)
|
63 |
+
return input_token_count + system_prompt_token_count
|
64 |
+
return input_token_count
|
65 |
+
|
66 |
+
def billing_info(self):
|
67 |
+
try:
|
68 |
+
curr_time = datetime.datetime.now()
|
69 |
+
last_day_of_month = get_last_day_of_month(
|
70 |
+
curr_time).strftime("%Y-%m-%d")
|
71 |
+
first_day_of_month = curr_time.replace(day=1).strftime("%Y-%m-%d")
|
72 |
+
usage_url = f"{shared.state.usage_api_url}?start_date={first_day_of_month}&end_date={last_day_of_month}"
|
73 |
+
try:
|
74 |
+
usage_data = self._get_billing_data(usage_url)
|
75 |
+
except Exception as e:
|
76 |
+
# logging.error(f"获取API使用情况失败: " + str(e))
|
77 |
+
if "Invalid authorization header" in str(e):
|
78 |
+
return i18n("**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id")
|
79 |
+
elif "Incorrect API key provided: sess" in str(e):
|
80 |
+
return i18n("**获取API使用情况失败**,sensitive_id错误或已过期")
|
81 |
+
return i18n("**获取API使用情况失败**")
|
82 |
+
# rounded_usage = "{:.5f}".format(usage_data["total_usage"] / 100)
|
83 |
+
rounded_usage = round(usage_data["total_usage"] / 100, 5)
|
84 |
+
usage_percent = round(usage_data["total_usage"] / usage_limit, 2)
|
85 |
+
from ..webui import get_html
|
86 |
+
|
87 |
+
# return i18n("**本月使用金额** ") + f"\u3000 ${rounded_usage}"
|
88 |
+
return get_html("billing_info.html").format(
|
89 |
+
label = i18n("本月使用金额"),
|
90 |
+
usage_percent = usage_percent,
|
91 |
+
rounded_usage = rounded_usage,
|
92 |
+
usage_limit = usage_limit
|
93 |
+
)
|
94 |
+
except requests.exceptions.ConnectTimeout:
|
95 |
+
status_text = (
|
96 |
+
STANDARD_ERROR_MSG + CONNECTION_TIMEOUT_MSG + ERROR_RETRIEVE_MSG
|
97 |
+
)
|
98 |
+
return status_text
|
99 |
+
except requests.exceptions.ReadTimeout:
|
100 |
+
status_text = STANDARD_ERROR_MSG + READ_TIMEOUT_MSG + ERROR_RETRIEVE_MSG
|
101 |
+
return status_text
|
102 |
+
except Exception as e:
|
103 |
+
import traceback
|
104 |
+
traceback.print_exc()
|
105 |
+
logging.error(i18n("获取API使用情况失败:") + str(e))
|
106 |
+
return STANDARD_ERROR_MSG + ERROR_RETRIEVE_MSG
|
107 |
+
|
108 |
+
def set_token_upper_limit(self, new_upper_limit):
|
109 |
+
pass
|
110 |
+
|
111 |
+
@shared.state.switching_api_key # 在不开启多账号模式的时候,这个装饰器不会起作用
|
112 |
+
def _get_response(self, stream=False):
|
113 |
+
openai_api_key = self.api_key
|
114 |
+
system_prompt = self.system_prompt
|
115 |
+
history = self.history
|
116 |
+
logging.debug(colorama.Fore.YELLOW +
|
117 |
+
f"{history}" + colorama.Fore.RESET)
|
118 |
+
headers = {
|
119 |
+
"Content-Type": "application/json",
|
120 |
+
"Authorization": f"Bearer {openai_api_key}",
|
121 |
+
}
|
122 |
+
|
123 |
+
if system_prompt is not None:
|
124 |
+
history = [construct_system(system_prompt), *history]
|
125 |
+
|
126 |
+
payload = {
|
127 |
+
"model": self.model_name,
|
128 |
+
"messages": history,
|
129 |
+
"temperature": self.temperature,
|
130 |
+
"top_p": self.top_p,
|
131 |
+
"n": self.n_choices,
|
132 |
+
"stream": stream,
|
133 |
+
"presence_penalty": self.presence_penalty,
|
134 |
+
"frequency_penalty": self.frequency_penalty,
|
135 |
+
}
|
136 |
+
|
137 |
+
if self.max_generation_token is not None:
|
138 |
+
payload["max_tokens"] = self.max_generation_token
|
139 |
+
if self.stop_sequence is not None:
|
140 |
+
payload["stop"] = self.stop_sequence
|
141 |
+
if self.logit_bias is not None:
|
142 |
+
payload["logit_bias"] = self.logit_bias
|
143 |
+
if self.user_identifier:
|
144 |
+
payload["user"] = self.user_identifier
|
145 |
+
|
146 |
+
if stream:
|
147 |
+
timeout = TIMEOUT_STREAMING
|
148 |
+
else:
|
149 |
+
timeout = TIMEOUT_ALL
|
150 |
+
|
151 |
+
# 如果有自定义的api-host,使用自定义host发送请求,否则使用默认设置发送请求
|
152 |
+
if shared.state.chat_completion_url != CHAT_COMPLETION_URL:
|
153 |
+
logging.debug(f"使用自定义API URL: {shared.state.chat_completion_url}")
|
154 |
+
|
155 |
+
with retrieve_proxy():
|
156 |
+
try:
|
157 |
+
response = requests.post(
|
158 |
+
shared.state.chat_completion_url,
|
159 |
+
headers=headers,
|
160 |
+
json=payload,
|
161 |
+
stream=stream,
|
162 |
+
timeout=timeout,
|
163 |
+
)
|
164 |
+
except:
|
165 |
+
traceback.print_exc()
|
166 |
+
return None
|
167 |
+
return response
|
168 |
+
|
169 |
+
def _refresh_header(self):
|
170 |
+
self.headers = {
|
171 |
+
"Content-Type": "application/json",
|
172 |
+
"Authorization": f"Bearer {sensitive_id}",
|
173 |
+
}
|
174 |
+
|
175 |
+
|
176 |
+
def _get_billing_data(self, billing_url):
|
177 |
+
with retrieve_proxy():
|
178 |
+
response = requests.get(
|
179 |
+
billing_url,
|
180 |
+
headers=self.headers,
|
181 |
+
timeout=TIMEOUT_ALL,
|
182 |
+
)
|
183 |
+
|
184 |
+
if response.status_code == 200:
|
185 |
+
data = response.json()
|
186 |
+
return data
|
187 |
+
else:
|
188 |
+
raise Exception(
|
189 |
+
f"API request failed with status code {response.status_code}: {response.text}"
|
190 |
+
)
|
191 |
+
|
192 |
+
def _decode_chat_response(self, response):
|
193 |
+
error_msg = ""
|
194 |
+
for chunk in response.iter_lines():
|
195 |
+
if chunk:
|
196 |
+
chunk = chunk.decode()
|
197 |
+
chunk_length = len(chunk)
|
198 |
+
try:
|
199 |
+
chunk = json.loads(chunk[6:])
|
200 |
+
except:
|
201 |
+
print(i18n("JSON解析错误,收到的内容: ") + f"{chunk}")
|
202 |
+
error_msg += chunk
|
203 |
+
continue
|
204 |
+
try:
|
205 |
+
if chunk_length > 6 and "delta" in chunk["choices"][0]:
|
206 |
+
if "finish_reason" in chunk["choices"][0]:
|
207 |
+
finish_reason = chunk["choices"][0]["finish_reason"]
|
208 |
+
else:
|
209 |
+
finish_reason = chunk["finish_reason"]
|
210 |
+
if finish_reason == "stop":
|
211 |
+
break
|
212 |
+
try:
|
213 |
+
yield chunk["choices"][0]["delta"]["content"]
|
214 |
+
except Exception as e:
|
215 |
+
# logging.error(f"Error: {e}")
|
216 |
+
continue
|
217 |
+
except:
|
218 |
+
print(f"ERROR: {chunk}")
|
219 |
+
continue
|
220 |
+
if error_msg and not error_msg=="data: [DONE]":
|
221 |
+
raise Exception(error_msg)
|
222 |
+
|
223 |
+
def set_key(self, new_access_key):
|
224 |
+
ret = super().set_key(new_access_key)
|
225 |
+
self._refresh_header()
|
226 |
+
return ret
|
227 |
+
|
228 |
+
def _single_query_at_once(self, history, temperature=1.0):
|
229 |
+
timeout = TIMEOUT_ALL
|
230 |
+
headers = {
|
231 |
+
"Content-Type": "application/json",
|
232 |
+
"Authorization": f"Bearer {self.api_key}",
|
233 |
+
"temperature": f"{temperature}",
|
234 |
+
}
|
235 |
+
payload = {
|
236 |
+
"model": self.model_name,
|
237 |
+
"messages": history,
|
238 |
+
}
|
239 |
+
# 如果有自定义的api-host,使用自定义host发送请求,否则使用默认设置发送请求
|
240 |
+
if shared.state.chat_completion_url != CHAT_COMPLETION_URL:
|
241 |
+
logging.debug(f"使用自定义API URL: {shared.state.chat_completion_url}")
|
242 |
+
|
243 |
+
with retrieve_proxy():
|
244 |
+
response = requests.post(
|
245 |
+
shared.state.chat_completion_url,
|
246 |
+
headers=headers,
|
247 |
+
json=payload,
|
248 |
+
stream=False,
|
249 |
+
timeout=timeout,
|
250 |
+
)
|
251 |
+
|
252 |
+
return response
|
253 |
+
|
254 |
+
|
255 |
+
def auto_name_chat_history(self, name_chat_method, user_question, chatbot, user_name, single_turn_checkbox):
|
256 |
+
if len(self.history) == 2 and not single_turn_checkbox and not hide_history_when_not_logged_in:
|
257 |
+
user_question = self.history[0]["content"]
|
258 |
+
if name_chat_method == i18n("模型自动总结(消耗tokens)"):
|
259 |
+
ai_answer = self.history[1]["content"]
|
260 |
+
try:
|
261 |
+
history = [
|
262 |
+
{ "role": "system", "content": SUMMARY_CHAT_SYSTEM_PROMPT},
|
263 |
+
{ "role": "user", "content": f"Please write a title based on the following conversation:\n---\nUser: {user_question}\nAssistant: {ai_answer}"}
|
264 |
+
]
|
265 |
+
response = self._single_query_at_once(history, temperature=0.0)
|
266 |
+
response = json.loads(response.text)
|
267 |
+
content = response["choices"][0]["message"]["content"]
|
268 |
+
filename = replace_special_symbols(content) + ".json"
|
269 |
+
except Exception as e:
|
270 |
+
logging.info(f"自动命名失败。{e}")
|
271 |
+
filename = replace_special_symbols(user_question)[:16] + ".json"
|
272 |
+
return self.rename_chat_history(filename, chatbot, user_name)
|
273 |
+
elif name_chat_method == i18n("第一条提问"):
|
274 |
+
filename = replace_special_symbols(user_question)[:16] + ".json"
|
275 |
+
return self.rename_chat_history(filename, chatbot, user_name)
|
276 |
+
else:
|
277 |
+
return gr.update()
|
278 |
+
else:
|
279 |
+
return gr.update()
|
modules/models/OpenAIInstruct.py
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import openai
|
2 |
+
from .base_model import BaseLLMModel
|
3 |
+
from .. import shared
|
4 |
+
from ..config import retrieve_proxy
|
5 |
+
|
6 |
+
|
7 |
+
class OpenAI_Instruct_Client(BaseLLMModel):
|
8 |
+
def __init__(self, model_name, api_key, user_name="") -> None:
|
9 |
+
super().__init__(model_name=model_name, user=user_name)
|
10 |
+
self.api_key = api_key
|
11 |
+
|
12 |
+
def _get_instruct_style_input(self):
|
13 |
+
return "\n\n".join([item["content"] for item in self.history])
|
14 |
+
|
15 |
+
@shared.state.switching_api_key
|
16 |
+
def get_answer_at_once(self):
|
17 |
+
prompt = self._get_instruct_style_input()
|
18 |
+
with retrieve_proxy():
|
19 |
+
response = openai.Completion.create(
|
20 |
+
api_key=self.api_key,
|
21 |
+
api_base=shared.state.openai_api_base,
|
22 |
+
model=self.model_name,
|
23 |
+
prompt=prompt,
|
24 |
+
temperature=self.temperature,
|
25 |
+
top_p=self.top_p,
|
26 |
+
)
|
27 |
+
return response.choices[0].text.strip(), response.usage["total_tokens"]
|
modules/models/OpenAIVision.py
ADDED
@@ -0,0 +1,328 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import json
|
4 |
+
import logging
|
5 |
+
import traceback
|
6 |
+
import base64
|
7 |
+
|
8 |
+
import colorama
|
9 |
+
import requests
|
10 |
+
from io import BytesIO
|
11 |
+
import uuid
|
12 |
+
|
13 |
+
import requests
|
14 |
+
from PIL import Image
|
15 |
+
|
16 |
+
from .. import shared
|
17 |
+
from ..config import retrieve_proxy, sensitive_id, usage_limit
|
18 |
+
from ..index_func import *
|
19 |
+
from ..presets import *
|
20 |
+
from ..utils import *
|
21 |
+
from .base_model import BaseLLMModel
|
22 |
+
|
23 |
+
|
24 |
+
class OpenAIVisionClient(BaseLLMModel):
|
25 |
+
def __init__(
|
26 |
+
self,
|
27 |
+
model_name,
|
28 |
+
api_key,
|
29 |
+
system_prompt=INITIAL_SYSTEM_PROMPT,
|
30 |
+
temperature=1.0,
|
31 |
+
top_p=1.0,
|
32 |
+
user_name=""
|
33 |
+
) -> None:
|
34 |
+
super().__init__(
|
35 |
+
model_name=MODEL_METADATA[model_name]["model_name"],
|
36 |
+
temperature=temperature,
|
37 |
+
top_p=top_p,
|
38 |
+
system_prompt=system_prompt,
|
39 |
+
user=user_name
|
40 |
+
)
|
41 |
+
self.api_key = api_key
|
42 |
+
self.need_api_key = True
|
43 |
+
self.max_generation_token = 4096
|
44 |
+
self.images = []
|
45 |
+
self._refresh_header()
|
46 |
+
|
47 |
+
def get_answer_stream_iter(self):
|
48 |
+
response = self._get_response(stream=True)
|
49 |
+
if response is not None:
|
50 |
+
iter = self._decode_chat_response(response)
|
51 |
+
partial_text = ""
|
52 |
+
for i in iter:
|
53 |
+
partial_text += i
|
54 |
+
yield partial_text
|
55 |
+
else:
|
56 |
+
yield STANDARD_ERROR_MSG + GENERAL_ERROR_MSG
|
57 |
+
|
58 |
+
def get_answer_at_once(self):
|
59 |
+
response = self._get_response()
|
60 |
+
response = json.loads(response.text)
|
61 |
+
content = response["choices"][0]["message"]["content"]
|
62 |
+
total_token_count = response["usage"]["total_tokens"]
|
63 |
+
return content, total_token_count
|
64 |
+
|
65 |
+
def try_read_image(self, filepath):
|
66 |
+
def is_image_file(filepath):
|
67 |
+
# 判断文件是否为图片
|
68 |
+
valid_image_extensions = [
|
69 |
+
".jpg", ".jpeg", ".png", ".bmp", ".gif", ".tiff"]
|
70 |
+
file_extension = os.path.splitext(filepath)[1].lower()
|
71 |
+
return file_extension in valid_image_extensions
|
72 |
+
def image_to_base64(image_path):
|
73 |
+
# 打开并加载图片
|
74 |
+
img = Image.open(image_path)
|
75 |
+
|
76 |
+
# 获取图片的宽度和高度
|
77 |
+
width, height = img.size
|
78 |
+
|
79 |
+
# 计算压缩比例,以确保最长边小于4096像素
|
80 |
+
max_dimension = 2048
|
81 |
+
scale_ratio = min(max_dimension / width, max_dimension / height)
|
82 |
+
|
83 |
+
if scale_ratio < 1:
|
84 |
+
# 按压缩比例调整图片大小
|
85 |
+
new_width = int(width * scale_ratio)
|
86 |
+
new_height = int(height * scale_ratio)
|
87 |
+
img = img.resize((new_width, new_height), Image.LANCZOS)
|
88 |
+
|
89 |
+
# 将图片转换为jpg格式的二进制数据
|
90 |
+
buffer = BytesIO()
|
91 |
+
if img.mode == "RGBA":
|
92 |
+
img = img.convert("RGB")
|
93 |
+
img.save(buffer, format='JPEG')
|
94 |
+
binary_image = buffer.getvalue()
|
95 |
+
|
96 |
+
# 对二进制数据进行Base64编码
|
97 |
+
base64_image = base64.b64encode(binary_image).decode('utf-8')
|
98 |
+
|
99 |
+
return base64_image
|
100 |
+
|
101 |
+
if is_image_file(filepath):
|
102 |
+
logging.info(f"读取图片文件: {filepath}")
|
103 |
+
base64_image = image_to_base64(filepath)
|
104 |
+
self.images.append({
|
105 |
+
"path": filepath,
|
106 |
+
"base64": base64_image,
|
107 |
+
})
|
108 |
+
|
109 |
+
def handle_file_upload(self, files, chatbot, language):
|
110 |
+
"""if the model accepts multi modal input, implement this function"""
|
111 |
+
if files:
|
112 |
+
for file in files:
|
113 |
+
if file.name:
|
114 |
+
self.try_read_image(file.name)
|
115 |
+
if self.images is not None:
|
116 |
+
chatbot = chatbot + [([image["path"] for image in self.images], None)]
|
117 |
+
return None, chatbot, None
|
118 |
+
|
119 |
+
def prepare_inputs(self, real_inputs, use_websearch, files, reply_language, chatbot):
|
120 |
+
fake_inputs = real_inputs
|
121 |
+
display_append = ""
|
122 |
+
limited_context = False
|
123 |
+
return limited_context, fake_inputs, display_append, real_inputs, chatbot
|
124 |
+
|
125 |
+
|
126 |
+
def count_token(self, user_input):
|
127 |
+
input_token_count = count_token(construct_user(user_input))
|
128 |
+
if self.system_prompt is not None and len(self.all_token_counts) == 0:
|
129 |
+
system_prompt_token_count = count_token(
|
130 |
+
construct_system(self.system_prompt)
|
131 |
+
)
|
132 |
+
return input_token_count + system_prompt_token_count
|
133 |
+
return input_token_count
|
134 |
+
|
135 |
+
def billing_info(self):
|
136 |
+
try:
|
137 |
+
curr_time = datetime.datetime.now()
|
138 |
+
last_day_of_month = get_last_day_of_month(
|
139 |
+
curr_time).strftime("%Y-%m-%d")
|
140 |
+
first_day_of_month = curr_time.replace(day=1).strftime("%Y-%m-%d")
|
141 |
+
usage_url = f"{shared.state.usage_api_url}?start_date={first_day_of_month}&end_date={last_day_of_month}"
|
142 |
+
try:
|
143 |
+
usage_data = self._get_billing_data(usage_url)
|
144 |
+
except Exception as e:
|
145 |
+
# logging.error(f"获取API使用情况失败: " + str(e))
|
146 |
+
if "Invalid authorization header" in str(e):
|
147 |
+
return i18n("**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id")
|
148 |
+
elif "Incorrect API key provided: sess" in str(e):
|
149 |
+
return i18n("**获取API使用情况失败**,sensitive_id错误或已过期")
|
150 |
+
return i18n("**获取API使用情况失败**")
|
151 |
+
# rounded_usage = "{:.5f}".format(usage_data["total_usage"] / 100)
|
152 |
+
rounded_usage = round(usage_data["total_usage"] / 100, 5)
|
153 |
+
usage_percent = round(usage_data["total_usage"] / usage_limit, 2)
|
154 |
+
from ..webui import get_html
|
155 |
+
|
156 |
+
# return i18n("**本月使用金额** ") + f"\u3000 ${rounded_usage}"
|
157 |
+
return get_html("billing_info.html").format(
|
158 |
+
label = i18n("本月使用金额"),
|
159 |
+
usage_percent = usage_percent,
|
160 |
+
rounded_usage = rounded_usage,
|
161 |
+
usage_limit = usage_limit
|
162 |
+
)
|
163 |
+
except requests.exceptions.ConnectTimeout:
|
164 |
+
status_text = (
|
165 |
+
STANDARD_ERROR_MSG + CONNECTION_TIMEOUT_MSG + ERROR_RETRIEVE_MSG
|
166 |
+
)
|
167 |
+
return status_text
|
168 |
+
except requests.exceptions.ReadTimeout:
|
169 |
+
status_text = STANDARD_ERROR_MSG + READ_TIMEOUT_MSG + ERROR_RETRIEVE_MSG
|
170 |
+
return status_text
|
171 |
+
except Exception as e:
|
172 |
+
import traceback
|
173 |
+
traceback.print_exc()
|
174 |
+
logging.error(i18n("获取API使用情况失败:") + str(e))
|
175 |
+
return STANDARD_ERROR_MSG + ERROR_RETRIEVE_MSG
|
176 |
+
|
177 |
+
def set_token_upper_limit(self, new_upper_limit):
|
178 |
+
pass
|
179 |
+
|
180 |
+
@shared.state.switching_api_key # 在不开启多账号模式的时候,这个装饰器不会起作用
|
181 |
+
def _get_response(self, stream=False):
|
182 |
+
openai_api_key = self.api_key
|
183 |
+
system_prompt = self.system_prompt
|
184 |
+
history = self.history
|
185 |
+
if self.images:
|
186 |
+
self.history[-1]["content"] = [
|
187 |
+
{"type": "text", "text": self.history[-1]["content"]},
|
188 |
+
*[{"type": "image_url", "image_url": "data:image/jpeg;base64,"+image["base64"]} for image in self.images]
|
189 |
+
]
|
190 |
+
self.images = []
|
191 |
+
logging.debug(colorama.Fore.YELLOW +
|
192 |
+
f"{history}" + colorama.Fore.RESET)
|
193 |
+
headers = {
|
194 |
+
"Content-Type": "application/json",
|
195 |
+
"Authorization": f"Bearer {openai_api_key}",
|
196 |
+
}
|
197 |
+
|
198 |
+
if system_prompt is not None:
|
199 |
+
history = [construct_system(system_prompt), *history]
|
200 |
+
|
201 |
+
payload = {
|
202 |
+
"model": self.model_name,
|
203 |
+
"messages": history,
|
204 |
+
"temperature": self.temperature,
|
205 |
+
"top_p": self.top_p,
|
206 |
+
"n": self.n_choices,
|
207 |
+
"stream": stream,
|
208 |
+
"presence_penalty": self.presence_penalty,
|
209 |
+
"frequency_penalty": self.frequency_penalty,
|
210 |
+
}
|
211 |
+
|
212 |
+
if self.max_generation_token is not None:
|
213 |
+
payload["max_tokens"] = self.max_generation_token
|
214 |
+
if self.stop_sequence is not None:
|
215 |
+
payload["stop"] = self.stop_sequence
|
216 |
+
if self.logit_bias is not None:
|
217 |
+
payload["logit_bias"] = self.logit_bias
|
218 |
+
if self.user_identifier:
|
219 |
+
payload["user"] = self.user_identifier
|
220 |
+
|
221 |
+
if stream:
|
222 |
+
timeout = TIMEOUT_STREAMING
|
223 |
+
else:
|
224 |
+
timeout = TIMEOUT_ALL
|
225 |
+
|
226 |
+
# 如果有自定义的api-host,使用自定义host发送请求,否则使用默认设置发送请求
|
227 |
+
if shared.state.chat_completion_url != CHAT_COMPLETION_URL:
|
228 |
+
logging.debug(f"使用自定义API URL: {shared.state.chat_completion_url}")
|
229 |
+
|
230 |
+
with retrieve_proxy():
|
231 |
+
try:
|
232 |
+
response = requests.post(
|
233 |
+
shared.state.chat_completion_url,
|
234 |
+
headers=headers,
|
235 |
+
json=payload,
|
236 |
+
stream=stream,
|
237 |
+
timeout=timeout,
|
238 |
+
)
|
239 |
+
except:
|
240 |
+
traceback.print_exc()
|
241 |
+
return None
|
242 |
+
return response
|
243 |
+
|
244 |
+
def _refresh_header(self):
|
245 |
+
self.headers = {
|
246 |
+
"Content-Type": "application/json",
|
247 |
+
"Authorization": f"Bearer {sensitive_id}",
|
248 |
+
}
|
249 |
+
|
250 |
+
|
251 |
+
def _get_billing_data(self, billing_url):
|
252 |
+
with retrieve_proxy():
|
253 |
+
response = requests.get(
|
254 |
+
billing_url,
|
255 |
+
headers=self.headers,
|
256 |
+
timeout=TIMEOUT_ALL,
|
257 |
+
)
|
258 |
+
|
259 |
+
if response.status_code == 200:
|
260 |
+
data = response.json()
|
261 |
+
return data
|
262 |
+
else:
|
263 |
+
raise Exception(
|
264 |
+
f"API request failed with status code {response.status_code}: {response.text}"
|
265 |
+
)
|
266 |
+
|
267 |
+
def _decode_chat_response(self, response):
|
268 |
+
error_msg = ""
|
269 |
+
for chunk in response.iter_lines():
|
270 |
+
if chunk:
|
271 |
+
chunk = chunk.decode()
|
272 |
+
chunk_length = len(chunk)
|
273 |
+
try:
|
274 |
+
chunk = json.loads(chunk[6:])
|
275 |
+
except:
|
276 |
+
print(i18n("JSON解析错误,收到的内容: ") + f"{chunk}")
|
277 |
+
error_msg += chunk
|
278 |
+
continue
|
279 |
+
try:
|
280 |
+
if chunk_length > 6 and "delta" in chunk["choices"][0]:
|
281 |
+
if "finish_details" in chunk["choices"][0]:
|
282 |
+
finish_reason = chunk["choices"][0]["finish_details"]
|
283 |
+
else:
|
284 |
+
finish_reason = chunk["finish_details"]
|
285 |
+
if finish_reason == "stop":
|
286 |
+
break
|
287 |
+
try:
|
288 |
+
yield chunk["choices"][0]["delta"]["content"]
|
289 |
+
except Exception as e:
|
290 |
+
# logging.error(f"Error: {e}")
|
291 |
+
continue
|
292 |
+
except:
|
293 |
+
traceback.print_exc()
|
294 |
+
print(f"ERROR: {chunk}")
|
295 |
+
continue
|
296 |
+
if error_msg and not error_msg=="data: [DONE]":
|
297 |
+
raise Exception(error_msg)
|
298 |
+
|
299 |
+
def set_key(self, new_access_key):
|
300 |
+
ret = super().set_key(new_access_key)
|
301 |
+
self._refresh_header()
|
302 |
+
return ret
|
303 |
+
|
304 |
+
def _single_query_at_once(self, history, temperature=1.0):
|
305 |
+
timeout = TIMEOUT_ALL
|
306 |
+
headers = {
|
307 |
+
"Content-Type": "application/json",
|
308 |
+
"Authorization": f"Bearer {self.api_key}",
|
309 |
+
"temperature": f"{temperature}",
|
310 |
+
}
|
311 |
+
payload = {
|
312 |
+
"model": self.model_name,
|
313 |
+
"messages": history,
|
314 |
+
}
|
315 |
+
# 如果有自定义的api-host,使用自定义host发送请求,否则使用默认设置发送请求
|
316 |
+
if shared.state.chat_completion_url != CHAT_COMPLETION_URL:
|
317 |
+
logging.debug(f"使用自定义API URL: {shared.state.chat_completion_url}")
|
318 |
+
|
319 |
+
with retrieve_proxy():
|
320 |
+
response = requests.post(
|
321 |
+
shared.state.chat_completion_url,
|
322 |
+
headers=headers,
|
323 |
+
json=payload,
|
324 |
+
stream=False,
|
325 |
+
timeout=timeout,
|
326 |
+
)
|
327 |
+
|
328 |
+
return response
|
modules/models/Qwen.py
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
2 |
+
from transformers.generation import GenerationConfig
|
3 |
+
import logging
|
4 |
+
import colorama
|
5 |
+
from .base_model import BaseLLMModel
|
6 |
+
from ..presets import MODEL_METADATA
|
7 |
+
|
8 |
+
|
9 |
+
class Qwen_Client(BaseLLMModel):
|
10 |
+
def __init__(self, model_name, user_name="") -> None:
|
11 |
+
super().__init__(model_name=model_name, user=user_name)
|
12 |
+
self.tokenizer = AutoTokenizer.from_pretrained(MODEL_METADATA[model_name]["repo_id"], trust_remote_code=True, resume_download=True)
|
13 |
+
self.model = AutoModelForCausalLM.from_pretrained(MODEL_METADATA[model_name]["repo_id"], device_map="auto", trust_remote_code=True, resume_download=True).eval()
|
14 |
+
|
15 |
+
def generation_config(self):
|
16 |
+
return GenerationConfig.from_dict({
|
17 |
+
"chat_format": "chatml",
|
18 |
+
"do_sample": True,
|
19 |
+
"eos_token_id": 151643,
|
20 |
+
"max_length": self.token_upper_limit,
|
21 |
+
"max_new_tokens": 512,
|
22 |
+
"max_window_size": 6144,
|
23 |
+
"pad_token_id": 151643,
|
24 |
+
"top_k": 0,
|
25 |
+
"top_p": self.top_p,
|
26 |
+
"transformers_version": "4.33.2",
|
27 |
+
"trust_remote_code": True,
|
28 |
+
"temperature": self.temperature,
|
29 |
+
})
|
30 |
+
|
31 |
+
def _get_glm_style_input(self):
|
32 |
+
history = [x["content"] for x in self.history]
|
33 |
+
query = history.pop()
|
34 |
+
logging.debug(colorama.Fore.YELLOW +
|
35 |
+
f"{history}" + colorama.Fore.RESET)
|
36 |
+
assert (
|
37 |
+
len(history) % 2 == 0
|
38 |
+
), f"History should be even length. current history is: {history}"
|
39 |
+
history = [[history[i], history[i + 1]]
|
40 |
+
for i in range(0, len(history), 2)]
|
41 |
+
return history, query
|
42 |
+
|
43 |
+
def get_answer_at_once(self):
|
44 |
+
history, query = self._get_glm_style_input()
|
45 |
+
self.model.generation_config = self.generation_config()
|
46 |
+
response, history = self.model.chat(self.tokenizer, query, history=history)
|
47 |
+
return response, len(response)
|
48 |
+
|
49 |
+
def get_answer_stream_iter(self):
|
50 |
+
history, query = self._get_glm_style_input()
|
51 |
+
self.model.generation_config = self.generation_config()
|
52 |
+
for response in self.model.chat_stream(
|
53 |
+
self.tokenizer,
|
54 |
+
query,
|
55 |
+
history,
|
56 |
+
):
|
57 |
+
yield response
|
modules/models/XMChat.py
ADDED
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import base64
|
4 |
+
import json
|
5 |
+
import logging
|
6 |
+
import os
|
7 |
+
import uuid
|
8 |
+
from io import BytesIO
|
9 |
+
|
10 |
+
import requests
|
11 |
+
from PIL import Image
|
12 |
+
|
13 |
+
from ..index_func import *
|
14 |
+
from ..presets import *
|
15 |
+
from ..utils import *
|
16 |
+
from .base_model import BaseLLMModel
|
17 |
+
|
18 |
+
|
19 |
+
class XMChat(BaseLLMModel):
|
20 |
+
def __init__(self, api_key, user_name=""):
|
21 |
+
super().__init__(model_name="xmchat", user=user_name)
|
22 |
+
self.api_key = api_key
|
23 |
+
self.session_id = None
|
24 |
+
self.reset()
|
25 |
+
self.image_bytes = None
|
26 |
+
self.image_path = None
|
27 |
+
self.xm_history = []
|
28 |
+
self.url = "https://xmbot.net/web"
|
29 |
+
self.last_conv_id = None
|
30 |
+
|
31 |
+
def reset(self, remain_system_prompt=False):
|
32 |
+
self.session_id = str(uuid.uuid4())
|
33 |
+
self.last_conv_id = None
|
34 |
+
return super().reset()
|
35 |
+
|
36 |
+
def image_to_base64(self, image_path):
|
37 |
+
# 打开并加载图片
|
38 |
+
img = Image.open(image_path)
|
39 |
+
|
40 |
+
# 获取图片的宽度和高度
|
41 |
+
width, height = img.size
|
42 |
+
|
43 |
+
# 计算压缩比例,以确保最长边小于4096像素
|
44 |
+
max_dimension = 2048
|
45 |
+
scale_ratio = min(max_dimension / width, max_dimension / height)
|
46 |
+
|
47 |
+
if scale_ratio < 1:
|
48 |
+
# 按压缩比例调整图片大小
|
49 |
+
new_width = int(width * scale_ratio)
|
50 |
+
new_height = int(height * scale_ratio)
|
51 |
+
img = img.resize((new_width, new_height), Image.LANCZOS)
|
52 |
+
|
53 |
+
# 将图片转换为jpg格式的二进制数据
|
54 |
+
buffer = BytesIO()
|
55 |
+
if img.mode == "RGBA":
|
56 |
+
img = img.convert("RGB")
|
57 |
+
img.save(buffer, format='JPEG')
|
58 |
+
binary_image = buffer.getvalue()
|
59 |
+
|
60 |
+
# 对二进制数据进行Base64编码
|
61 |
+
base64_image = base64.b64encode(binary_image).decode('utf-8')
|
62 |
+
|
63 |
+
return base64_image
|
64 |
+
|
65 |
+
def try_read_image(self, filepath):
|
66 |
+
def is_image_file(filepath):
|
67 |
+
# 判断文件是否为图片
|
68 |
+
valid_image_extensions = [
|
69 |
+
".jpg", ".jpeg", ".png", ".bmp", ".gif", ".tiff"]
|
70 |
+
file_extension = os.path.splitext(filepath)[1].lower()
|
71 |
+
return file_extension in valid_image_extensions
|
72 |
+
|
73 |
+
if is_image_file(filepath):
|
74 |
+
logging.info(f"读取图片文件: {filepath}")
|
75 |
+
self.image_bytes = self.image_to_base64(filepath)
|
76 |
+
self.image_path = filepath
|
77 |
+
else:
|
78 |
+
self.image_bytes = None
|
79 |
+
self.image_path = None
|
80 |
+
|
81 |
+
def like(self):
|
82 |
+
if self.last_conv_id is None:
|
83 |
+
return "点赞失败,你还没发送过消息"
|
84 |
+
data = {
|
85 |
+
"uuid": self.last_conv_id,
|
86 |
+
"appraise": "good"
|
87 |
+
}
|
88 |
+
requests.post(self.url, json=data)
|
89 |
+
return "👍点赞成功,感谢反馈~"
|
90 |
+
|
91 |
+
def dislike(self):
|
92 |
+
if self.last_conv_id is None:
|
93 |
+
return "点踩失败,你还没发送过消息"
|
94 |
+
data = {
|
95 |
+
"uuid": self.last_conv_id,
|
96 |
+
"appraise": "bad"
|
97 |
+
}
|
98 |
+
requests.post(self.url, json=data)
|
99 |
+
return "👎点踩成功,感谢反馈~"
|
100 |
+
|
101 |
+
def prepare_inputs(self, real_inputs, use_websearch, files, reply_language, chatbot):
|
102 |
+
fake_inputs = real_inputs
|
103 |
+
display_append = ""
|
104 |
+
limited_context = False
|
105 |
+
return limited_context, fake_inputs, display_append, real_inputs, chatbot
|
106 |
+
|
107 |
+
def handle_file_upload(self, files, chatbot, language):
|
108 |
+
"""if the model accepts multi modal input, implement this function"""
|
109 |
+
if files:
|
110 |
+
for file in files:
|
111 |
+
if file.name:
|
112 |
+
logging.info(f"尝试读取图像: {file.name}")
|
113 |
+
self.try_read_image(file.name)
|
114 |
+
if self.image_path is not None:
|
115 |
+
chatbot = chatbot + [((self.image_path,), None)]
|
116 |
+
if self.image_bytes is not None:
|
117 |
+
logging.info("使用图片作为输入")
|
118 |
+
# XMChat的一轮对话中实际上只能处理一张图片
|
119 |
+
self.reset()
|
120 |
+
conv_id = str(uuid.uuid4())
|
121 |
+
data = {
|
122 |
+
"user_id": self.api_key,
|
123 |
+
"session_id": self.session_id,
|
124 |
+
"uuid": conv_id,
|
125 |
+
"data_type": "imgbase64",
|
126 |
+
"data": self.image_bytes
|
127 |
+
}
|
128 |
+
response = requests.post(self.url, json=data)
|
129 |
+
response = json.loads(response.text)
|
130 |
+
logging.info(f"图片回复: {response['data']}")
|
131 |
+
return None, chatbot, None
|
132 |
+
|
133 |
+
def get_answer_at_once(self):
|
134 |
+
question = self.history[-1]["content"]
|
135 |
+
conv_id = str(uuid.uuid4())
|
136 |
+
self.last_conv_id = conv_id
|
137 |
+
data = {
|
138 |
+
"user_id": self.api_key,
|
139 |
+
"session_id": self.session_id,
|
140 |
+
"uuid": conv_id,
|
141 |
+
"data_type": "text",
|
142 |
+
"data": question
|
143 |
+
}
|
144 |
+
response = requests.post(self.url, json=data)
|
145 |
+
try:
|
146 |
+
response = json.loads(response.text)
|
147 |
+
return response["data"], len(response["data"])
|
148 |
+
except Exception as e:
|
149 |
+
return response.text, len(response.text)
|
modules/models/base_model.py
CHANGED
@@ -10,6 +10,7 @@ import requests
|
|
10 |
import urllib3
|
11 |
import traceback
|
12 |
import pathlib
|
|
|
13 |
|
14 |
from tqdm import tqdm
|
15 |
import colorama
|
@@ -142,13 +143,23 @@ class ModelType(Enum):
|
|
142 |
GooglePaLM = 9
|
143 |
LangchainChat = 10
|
144 |
Midjourney = 11
|
|
|
|
|
|
|
|
|
|
|
145 |
|
146 |
@classmethod
|
147 |
def get_type(cls, model_name: str):
|
148 |
model_type = None
|
149 |
model_name_lower = model_name.lower()
|
150 |
if "gpt" in model_name_lower:
|
151 |
-
|
|
|
|
|
|
|
|
|
|
|
152 |
elif "chatglm" in model_name_lower:
|
153 |
model_type = ModelType.ChatGLM
|
154 |
elif "llama" in model_name_lower or "alpaca" in model_name_lower:
|
@@ -171,8 +182,14 @@ class ModelType(Enum):
|
|
171 |
model_type = ModelType.Midjourney
|
172 |
elif "azure" in model_name_lower or "api" in model_name_lower:
|
173 |
model_type = ModelType.LangchainChat
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
else:
|
175 |
-
model_type = ModelType.
|
176 |
return model_type
|
177 |
|
178 |
|
@@ -196,7 +213,7 @@ class BaseLLMModel:
|
|
196 |
self.model_name = model_name
|
197 |
self.model_type = ModelType.get_type(model_name)
|
198 |
try:
|
199 |
-
self.token_upper_limit =
|
200 |
except KeyError:
|
201 |
self.token_upper_limit = DEFAULT_TOKEN_LIMIT
|
202 |
self.interrupted = False
|
@@ -204,6 +221,7 @@ class BaseLLMModel:
|
|
204 |
self.api_key = None
|
205 |
self.need_api_key = False
|
206 |
self.single_turn = False
|
|
|
207 |
|
208 |
self.temperature = temperature
|
209 |
self.top_p = top_p
|
@@ -242,7 +260,7 @@ class BaseLLMModel:
|
|
242 |
|
243 |
def billing_info(self):
|
244 |
"""get billing infomation, inplement if needed"""
|
245 |
-
logging.warning("billing info not implemented, using default")
|
246 |
return BILLING_NOT_APPLICABLE_MSG
|
247 |
|
248 |
def count_token(self, user_input):
|
@@ -269,9 +287,12 @@ class BaseLLMModel:
|
|
269 |
if display_append:
|
270 |
display_append = '\n\n<hr class="append-display no-in-raw" />' + display_append
|
271 |
partial_text = ""
|
|
|
272 |
for partial_text in stream_iter:
|
|
|
|
|
273 |
chatbot[-1] = (chatbot[-1][0], partial_text + display_append)
|
274 |
-
self.all_token_counts[-1] +=
|
275 |
status_text = self.token_message()
|
276 |
yield get_return_value()
|
277 |
if self.interrupted:
|
@@ -334,41 +355,55 @@ class BaseLLMModel:
|
|
334 |
chatbot.append([i18n("上传了")+str(len(files))+"个文件", summary])
|
335 |
return chatbot, status
|
336 |
|
337 |
-
def prepare_inputs(self, real_inputs, use_websearch, files, reply_language, chatbot):
|
338 |
-
fake_inputs = None
|
339 |
display_append = []
|
340 |
limited_context = False
|
341 |
-
|
|
|
|
|
|
|
342 |
if files:
|
343 |
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
|
344 |
from langchain.vectorstores.base import VectorStoreRetriever
|
345 |
limited_context = True
|
346 |
msg = "加载索引中……"
|
347 |
logging.info(msg)
|
348 |
-
index = construct_index(self.api_key, file_src=files)
|
349 |
assert index is not None, "获取索引失败"
|
350 |
msg = "索引获取成功,生成回答中……"
|
351 |
logging.info(msg)
|
352 |
with retrieve_proxy():
|
353 |
-
retriever = VectorStoreRetriever(vectorstore=index, search_type="
|
354 |
-
|
355 |
-
|
356 |
-
|
|
|
|
|
|
|
|
|
357 |
reference_results = [[d.page_content.strip("�"), os.path.basename(
|
358 |
d.metadata["source"])] for d in relevant_documents]
|
359 |
reference_results = add_source_numbers(reference_results)
|
360 |
display_append = add_details(reference_results)
|
361 |
display_append = "\n\n" + "".join(display_append)
|
362 |
-
real_inputs
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
368 |
elif use_websearch:
|
369 |
search_results = []
|
370 |
with DDGS() as ddgs:
|
371 |
-
ddgs_gen = ddgs.text(
|
372 |
for r in islice(ddgs_gen, 10):
|
373 |
search_results.append(r)
|
374 |
reference_results = []
|
@@ -384,12 +419,20 @@ class BaseLLMModel:
|
|
384 |
# display_append = "<ol>\n\n" + "".join(display_append) + "</ol>"
|
385 |
display_append = '<div class = "source-a">' + \
|
386 |
"".join(display_append) + '</div>'
|
387 |
-
real_inputs
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
393 |
else:
|
394 |
display_append = ""
|
395 |
return limited_context, fake_inputs, display_append, real_inputs, chatbot
|
@@ -406,12 +449,21 @@ class BaseLLMModel:
|
|
406 |
): # repetition_penalty, top_k
|
407 |
|
408 |
status_text = "开始生成回答……"
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
413 |
if should_check_token_count:
|
414 |
-
|
|
|
|
|
|
|
415 |
if reply_language == "跟随问题语言(不稳定)":
|
416 |
reply_language = "the same language as the question, such as English, 中文, 日本語, Español, Français, or Deutsch."
|
417 |
|
@@ -426,25 +478,28 @@ class BaseLLMModel:
|
|
426 |
):
|
427 |
status_text = STANDARD_ERROR_MSG + NO_APIKEY_MSG
|
428 |
logging.info(status_text)
|
429 |
-
chatbot.append((
|
430 |
if len(self.history) == 0:
|
431 |
-
self.history.append(construct_user(
|
432 |
self.history.append("")
|
433 |
self.all_token_counts.append(0)
|
434 |
else:
|
435 |
-
self.history[-2] = construct_user(
|
436 |
-
yield chatbot + [(
|
437 |
return
|
438 |
-
elif len(
|
439 |
status_text = STANDARD_ERROR_MSG + NO_INPUT_MSG
|
440 |
logging.info(status_text)
|
441 |
-
yield chatbot + [(
|
442 |
return
|
443 |
|
444 |
if self.single_turn:
|
445 |
self.history = []
|
446 |
self.all_token_counts = []
|
447 |
-
|
|
|
|
|
|
|
448 |
|
449 |
try:
|
450 |
if stream:
|
@@ -471,7 +526,7 @@ class BaseLLMModel:
|
|
471 |
status_text = STANDARD_ERROR_MSG + beautify_err_msg(str(e))
|
472 |
yield chatbot, status_text
|
473 |
|
474 |
-
if len(self.history) > 1 and self.history[-1]["content"] !=
|
475 |
logging.info(
|
476 |
"回答为:"
|
477 |
+ colorama.Fore.BLUE
|
@@ -512,13 +567,19 @@ class BaseLLMModel:
|
|
512 |
reply_language="中文",
|
513 |
):
|
514 |
logging.debug("重试中……")
|
515 |
-
if len(self.history) >
|
516 |
inputs = self.history[-2]["content"]
|
517 |
del self.history[-2:]
|
518 |
-
|
519 |
-
|
520 |
elif len(chatbot) > 0:
|
521 |
inputs = chatbot[-1][0]
|
|
|
|
|
|
|
|
|
|
|
|
|
522 |
else:
|
523 |
yield chatbot, f"{STANDARD_ERROR_MSG}上下文是空的"
|
524 |
return
|
@@ -613,13 +674,15 @@ class BaseLLMModel:
|
|
613 |
def set_single_turn(self, new_single_turn):
|
614 |
self.single_turn = new_single_turn
|
615 |
|
616 |
-
def reset(self):
|
617 |
self.history = []
|
618 |
self.all_token_counts = []
|
619 |
self.interrupted = False
|
620 |
-
|
621 |
-
|
622 |
-
|
|
|
|
|
623 |
|
624 |
def delete_first_conversation(self):
|
625 |
if self.history:
|
@@ -630,18 +693,18 @@ class BaseLLMModel:
|
|
630 |
def delete_last_conversation(self, chatbot):
|
631 |
if len(chatbot) > 0 and STANDARD_ERROR_MSG in chatbot[-1][1]:
|
632 |
msg = "由于包含报错信息,只删除chatbot记录"
|
633 |
-
chatbot
|
634 |
return chatbot, self.history
|
635 |
if len(self.history) > 0:
|
636 |
-
self.history.
|
637 |
-
self.history.pop()
|
638 |
if len(chatbot) > 0:
|
639 |
msg = "删除了一组chatbot对话"
|
640 |
-
chatbot
|
641 |
if len(self.all_token_counts) > 0:
|
642 |
msg = "删除了一组对话的token计数记录"
|
643 |
self.all_token_counts.pop()
|
644 |
msg = "删除了一组对话"
|
|
|
645 |
return chatbot, msg
|
646 |
|
647 |
def token_message(self, token_lst=None):
|
@@ -652,16 +715,36 @@ class BaseLLMModel:
|
|
652 |
token_sum += sum(token_lst[: i + 1])
|
653 |
return i18n("Token 计数: ") + f"{sum(token_lst)}" + i18n(",本次对话累计消耗了 ") + f"{token_sum} tokens"
|
654 |
|
655 |
-
def
|
656 |
if filename == "":
|
657 |
-
return
|
658 |
if not filename.endswith(".json"):
|
659 |
filename += ".json"
|
660 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
661 |
|
662 |
def auto_save(self, chatbot):
|
663 |
-
history_file_path
|
664 |
-
save_file(history_file_path, self.system_prompt,
|
665 |
self.history, chatbot, self.user_identifier)
|
666 |
|
667 |
def export_markdown(self, filename, chatbot, user_name):
|
@@ -669,19 +752,27 @@ class BaseLLMModel:
|
|
669 |
return
|
670 |
if not filename.endswith(".md"):
|
671 |
filename += ".md"
|
672 |
-
|
673 |
-
|
674 |
-
def load_chat_history(self,
|
675 |
-
logging.debug(f"{
|
676 |
-
|
677 |
-
|
678 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
679 |
try:
|
680 |
-
if
|
681 |
history_file_path = os.path.join(
|
682 |
-
HISTORY_DIR,
|
683 |
else:
|
684 |
-
history_file_path =
|
|
|
|
|
685 |
with open(history_file_path, "r", encoding="utf-8") as f:
|
686 |
json_s = json.load(f)
|
687 |
try:
|
@@ -697,13 +788,17 @@ class BaseLLMModel:
|
|
697 |
logging.info(new_history)
|
698 |
except:
|
699 |
pass
|
700 |
-
|
|
|
|
|
|
|
|
|
701 |
self.history = json_s["history"]
|
702 |
-
return os.path.basename(
|
703 |
except:
|
704 |
# 没有对话历史或者对话历史解析失败
|
705 |
-
logging.info(f"没有找到对话历史记录 {
|
706 |
-
return
|
707 |
|
708 |
def delete_chat_history(self, filename, user_name):
|
709 |
if filename == "CANCELED":
|
@@ -712,25 +807,29 @@ class BaseLLMModel:
|
|
712 |
return i18n("你没有选择任何对话历史"), gr.update(), gr.update()
|
713 |
if not filename.endswith(".json"):
|
714 |
filename += ".json"
|
715 |
-
if
|
716 |
history_file_path = os.path.join(HISTORY_DIR, user_name, filename)
|
717 |
else:
|
718 |
history_file_path = filename
|
|
|
719 |
try:
|
720 |
os.remove(history_file_path)
|
721 |
-
|
|
|
722 |
except:
|
723 |
logging.info(f"删除对话历史失败 {history_file_path}")
|
724 |
-
return i18n("对话历史")+filename+i18n("已经被删除啦"),
|
725 |
|
726 |
def auto_load(self):
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
history_file_path
|
733 |
-
|
|
|
|
|
734 |
|
735 |
def like(self):
|
736 |
"""like the last response, implement if needed
|
|
|
10 |
import urllib3
|
11 |
import traceback
|
12 |
import pathlib
|
13 |
+
import shutil
|
14 |
|
15 |
from tqdm import tqdm
|
16 |
import colorama
|
|
|
143 |
GooglePaLM = 9
|
144 |
LangchainChat = 10
|
145 |
Midjourney = 11
|
146 |
+
Spark = 12
|
147 |
+
OpenAIInstruct = 13
|
148 |
+
Claude = 14
|
149 |
+
Qwen = 15
|
150 |
+
OpenAIVision = 16
|
151 |
|
152 |
@classmethod
|
153 |
def get_type(cls, model_name: str):
|
154 |
model_type = None
|
155 |
model_name_lower = model_name.lower()
|
156 |
if "gpt" in model_name_lower:
|
157 |
+
if "instruct" in model_name_lower:
|
158 |
+
model_type = ModelType.OpenAIInstruct
|
159 |
+
elif "vision" in model_name_lower:
|
160 |
+
model_type = ModelType.OpenAIVision
|
161 |
+
else:
|
162 |
+
model_type = ModelType.OpenAI
|
163 |
elif "chatglm" in model_name_lower:
|
164 |
model_type = ModelType.ChatGLM
|
165 |
elif "llama" in model_name_lower or "alpaca" in model_name_lower:
|
|
|
182 |
model_type = ModelType.Midjourney
|
183 |
elif "azure" in model_name_lower or "api" in model_name_lower:
|
184 |
model_type = ModelType.LangchainChat
|
185 |
+
elif "星火大模型" in model_name_lower:
|
186 |
+
model_type = ModelType.Spark
|
187 |
+
elif "claude" in model_name_lower:
|
188 |
+
model_type = ModelType.Claude
|
189 |
+
elif "qwen" in model_name_lower:
|
190 |
+
model_type = ModelType.Qwen
|
191 |
else:
|
192 |
+
model_type = ModelType.LLaMA
|
193 |
return model_type
|
194 |
|
195 |
|
|
|
213 |
self.model_name = model_name
|
214 |
self.model_type = ModelType.get_type(model_name)
|
215 |
try:
|
216 |
+
self.token_upper_limit = MODEL_METADATA[model_name]["token_limit"]
|
217 |
except KeyError:
|
218 |
self.token_upper_limit = DEFAULT_TOKEN_LIMIT
|
219 |
self.interrupted = False
|
|
|
221 |
self.api_key = None
|
222 |
self.need_api_key = False
|
223 |
self.single_turn = False
|
224 |
+
self.history_file_path = get_first_history_name(user)
|
225 |
|
226 |
self.temperature = temperature
|
227 |
self.top_p = top_p
|
|
|
260 |
|
261 |
def billing_info(self):
|
262 |
"""get billing infomation, inplement if needed"""
|
263 |
+
# logging.warning("billing info not implemented, using default")
|
264 |
return BILLING_NOT_APPLICABLE_MSG
|
265 |
|
266 |
def count_token(self, user_input):
|
|
|
287 |
if display_append:
|
288 |
display_append = '\n\n<hr class="append-display no-in-raw" />' + display_append
|
289 |
partial_text = ""
|
290 |
+
token_increment = 1
|
291 |
for partial_text in stream_iter:
|
292 |
+
if type(partial_text) == tuple:
|
293 |
+
partial_text, token_increment = partial_text
|
294 |
chatbot[-1] = (chatbot[-1][0], partial_text + display_append)
|
295 |
+
self.all_token_counts[-1] += token_increment
|
296 |
status_text = self.token_message()
|
297 |
yield get_return_value()
|
298 |
if self.interrupted:
|
|
|
355 |
chatbot.append([i18n("上传了")+str(len(files))+"个文件", summary])
|
356 |
return chatbot, status
|
357 |
|
358 |
+
def prepare_inputs(self, real_inputs, use_websearch, files, reply_language, chatbot, load_from_cache_if_possible=True):
|
|
|
359 |
display_append = []
|
360 |
limited_context = False
|
361 |
+
if type(real_inputs) == list:
|
362 |
+
fake_inputs = real_inputs[0]['text']
|
363 |
+
else:
|
364 |
+
fake_inputs = real_inputs
|
365 |
if files:
|
366 |
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
|
367 |
from langchain.vectorstores.base import VectorStoreRetriever
|
368 |
limited_context = True
|
369 |
msg = "加载索引中……"
|
370 |
logging.info(msg)
|
371 |
+
index = construct_index(self.api_key, file_src=files, load_from_cache_if_possible=load_from_cache_if_possible)
|
372 |
assert index is not None, "获取索引失败"
|
373 |
msg = "索引获取成功,生成回答中……"
|
374 |
logging.info(msg)
|
375 |
with retrieve_proxy():
|
376 |
+
retriever = VectorStoreRetriever(vectorstore=index, search_type="similarity", search_kwargs={"k": 6})
|
377 |
+
# retriever = VectorStoreRetriever(vectorstore=index, search_type="similarity_score_threshold", search_kwargs={
|
378 |
+
# "k": 6, "score_threshold": 0.2})
|
379 |
+
try:
|
380 |
+
relevant_documents = retriever.get_relevant_documents(
|
381 |
+
fake_inputs)
|
382 |
+
except AssertionError:
|
383 |
+
return self.prepare_inputs(fake_inputs, use_websearch, files, reply_language, chatbot, load_from_cache_if_possible=False)
|
384 |
reference_results = [[d.page_content.strip("�"), os.path.basename(
|
385 |
d.metadata["source"])] for d in relevant_documents]
|
386 |
reference_results = add_source_numbers(reference_results)
|
387 |
display_append = add_details(reference_results)
|
388 |
display_append = "\n\n" + "".join(display_append)
|
389 |
+
if type(real_inputs) == list:
|
390 |
+
real_inputs[0]["text"] = (
|
391 |
+
replace_today(PROMPT_TEMPLATE)
|
392 |
+
.replace("{query_str}", fake_inputs)
|
393 |
+
.replace("{context_str}", "\n\n".join(reference_results))
|
394 |
+
.replace("{reply_language}", reply_language)
|
395 |
+
)
|
396 |
+
else:
|
397 |
+
real_inputs = (
|
398 |
+
replace_today(PROMPT_TEMPLATE)
|
399 |
+
.replace("{query_str}", real_inputs)
|
400 |
+
.replace("{context_str}", "\n\n".join(reference_results))
|
401 |
+
.replace("{reply_language}", reply_language)
|
402 |
+
)
|
403 |
elif use_websearch:
|
404 |
search_results = []
|
405 |
with DDGS() as ddgs:
|
406 |
+
ddgs_gen = ddgs.text(fake_inputs, backend="lite")
|
407 |
for r in islice(ddgs_gen, 10):
|
408 |
search_results.append(r)
|
409 |
reference_results = []
|
|
|
419 |
# display_append = "<ol>\n\n" + "".join(display_append) + "</ol>"
|
420 |
display_append = '<div class = "source-a">' + \
|
421 |
"".join(display_append) + '</div>'
|
422 |
+
if type(real_inputs) == list:
|
423 |
+
real_inputs[0]["text"] = (
|
424 |
+
replace_today(WEBSEARCH_PTOMPT_TEMPLATE)
|
425 |
+
.replace("{query}", fake_inputs)
|
426 |
+
.replace("{web_results}", "\n\n".join(reference_results))
|
427 |
+
.replace("{reply_language}", reply_language)
|
428 |
+
)
|
429 |
+
else:
|
430 |
+
real_inputs = (
|
431 |
+
replace_today(WEBSEARCH_PTOMPT_TEMPLATE)
|
432 |
+
.replace("{query}", fake_inputs)
|
433 |
+
.replace("{web_results}", "\n\n".join(reference_results))
|
434 |
+
.replace("{reply_language}", reply_language)
|
435 |
+
)
|
436 |
else:
|
437 |
display_append = ""
|
438 |
return limited_context, fake_inputs, display_append, real_inputs, chatbot
|
|
|
449 |
): # repetition_penalty, top_k
|
450 |
|
451 |
status_text = "开始生成回答……"
|
452 |
+
if type(inputs) == list:
|
453 |
+
logging.info(
|
454 |
+
"用户" + f"{self.user_identifier}" + "的输入为:" +
|
455 |
+
colorama.Fore.BLUE + "(" + str(len(inputs)-1) + " images) " + f"{inputs[0]['text']}" + colorama.Style.RESET_ALL
|
456 |
+
)
|
457 |
+
else:
|
458 |
+
logging.info(
|
459 |
+
"用户" + f"{self.user_identifier}" + "的输入为:" +
|
460 |
+
colorama.Fore.BLUE + f"{inputs}" + colorama.Style.RESET_ALL
|
461 |
+
)
|
462 |
if should_check_token_count:
|
463 |
+
if type(inputs) == list:
|
464 |
+
yield chatbot + [(inputs[0]['text'], "")], status_text
|
465 |
+
else:
|
466 |
+
yield chatbot + [(inputs, "")], status_text
|
467 |
if reply_language == "跟随问题语言(不稳定)":
|
468 |
reply_language = "the same language as the question, such as English, 中文, 日本語, Español, Français, or Deutsch."
|
469 |
|
|
|
478 |
):
|
479 |
status_text = STANDARD_ERROR_MSG + NO_APIKEY_MSG
|
480 |
logging.info(status_text)
|
481 |
+
chatbot.append((fake_inputs, ""))
|
482 |
if len(self.history) == 0:
|
483 |
+
self.history.append(construct_user(fake_inputs))
|
484 |
self.history.append("")
|
485 |
self.all_token_counts.append(0)
|
486 |
else:
|
487 |
+
self.history[-2] = construct_user(fake_inputs)
|
488 |
+
yield chatbot + [(fake_inputs, "")], status_text
|
489 |
return
|
490 |
+
elif len(fake_inputs.strip()) == 0:
|
491 |
status_text = STANDARD_ERROR_MSG + NO_INPUT_MSG
|
492 |
logging.info(status_text)
|
493 |
+
yield chatbot + [(fake_inputs, "")], status_text
|
494 |
return
|
495 |
|
496 |
if self.single_turn:
|
497 |
self.history = []
|
498 |
self.all_token_counts = []
|
499 |
+
if type(inputs) == list:
|
500 |
+
self.history.append(inputs)
|
501 |
+
else:
|
502 |
+
self.history.append(construct_user(inputs))
|
503 |
|
504 |
try:
|
505 |
if stream:
|
|
|
526 |
status_text = STANDARD_ERROR_MSG + beautify_err_msg(str(e))
|
527 |
yield chatbot, status_text
|
528 |
|
529 |
+
if len(self.history) > 1 and self.history[-1]["content"] != fake_inputs:
|
530 |
logging.info(
|
531 |
"回答为:"
|
532 |
+ colorama.Fore.BLUE
|
|
|
567 |
reply_language="中文",
|
568 |
):
|
569 |
logging.debug("重试中……")
|
570 |
+
if len(self.history) > 1:
|
571 |
inputs = self.history[-2]["content"]
|
572 |
del self.history[-2:]
|
573 |
+
if len(self.all_token_counts) > 0:
|
574 |
+
self.all_token_counts.pop()
|
575 |
elif len(chatbot) > 0:
|
576 |
inputs = chatbot[-1][0]
|
577 |
+
if '<div class="user-message">' in inputs:
|
578 |
+
inputs = inputs.split('<div class="user-message">')[1]
|
579 |
+
inputs = inputs.split("</div>")[0]
|
580 |
+
elif len(self.history) == 1:
|
581 |
+
inputs = self.history[-1]["content"]
|
582 |
+
del self.history[-1]
|
583 |
else:
|
584 |
yield chatbot, f"{STANDARD_ERROR_MSG}上下文是空的"
|
585 |
return
|
|
|
674 |
def set_single_turn(self, new_single_turn):
|
675 |
self.single_turn = new_single_turn
|
676 |
|
677 |
+
def reset(self, remain_system_prompt=False):
|
678 |
self.history = []
|
679 |
self.all_token_counts = []
|
680 |
self.interrupted = False
|
681 |
+
self.history_file_path = new_auto_history_filename(self.user_identifier)
|
682 |
+
history_name = self.history_file_path[:-5]
|
683 |
+
choices = [history_name] + get_history_names(self.user_identifier)
|
684 |
+
system_prompt = self.system_prompt if remain_system_prompt else ""
|
685 |
+
return [], self.token_message([0]), gr.Radio.update(choices=choices, value=history_name), system_prompt
|
686 |
|
687 |
def delete_first_conversation(self):
|
688 |
if self.history:
|
|
|
693 |
def delete_last_conversation(self, chatbot):
|
694 |
if len(chatbot) > 0 and STANDARD_ERROR_MSG in chatbot[-1][1]:
|
695 |
msg = "由于包含报错信息,只删除chatbot记录"
|
696 |
+
chatbot = chatbot[:-1]
|
697 |
return chatbot, self.history
|
698 |
if len(self.history) > 0:
|
699 |
+
self.history = self.history[:-2]
|
|
|
700 |
if len(chatbot) > 0:
|
701 |
msg = "删除了一组chatbot对话"
|
702 |
+
chatbot = chatbot[:-1]
|
703 |
if len(self.all_token_counts) > 0:
|
704 |
msg = "删除了一组对话的token计数记录"
|
705 |
self.all_token_counts.pop()
|
706 |
msg = "删除了一组对话"
|
707 |
+
self.auto_save(chatbot)
|
708 |
return chatbot, msg
|
709 |
|
710 |
def token_message(self, token_lst=None):
|
|
|
715 |
token_sum += sum(token_lst[: i + 1])
|
716 |
return i18n("Token 计数: ") + f"{sum(token_lst)}" + i18n(",本次对话累计消耗了 ") + f"{token_sum} tokens"
|
717 |
|
718 |
+
def rename_chat_history(self, filename, chatbot, user_name):
|
719 |
if filename == "":
|
720 |
+
return gr.update()
|
721 |
if not filename.endswith(".json"):
|
722 |
filename += ".json"
|
723 |
+
self.delete_chat_history(self.history_file_path, user_name)
|
724 |
+
# 命名重复检测
|
725 |
+
repeat_file_index = 2
|
726 |
+
full_path = os.path.join(HISTORY_DIR, user_name, filename)
|
727 |
+
while os.path.exists(full_path):
|
728 |
+
full_path = os.path.join(HISTORY_DIR, user_name, f"{repeat_file_index}_{filename}")
|
729 |
+
repeat_file_index += 1
|
730 |
+
filename = os.path.basename(full_path)
|
731 |
+
|
732 |
+
self.history_file_path = filename
|
733 |
+
save_file(filename, self.system_prompt, self.history, chatbot, user_name)
|
734 |
+
return init_history_list(user_name)
|
735 |
+
|
736 |
+
def auto_name_chat_history(self, name_chat_method, user_question, chatbot, user_name, single_turn_checkbox):
|
737 |
+
if len(self.history) == 2 and not single_turn_checkbox:
|
738 |
+
user_question = self.history[0]["content"]
|
739 |
+
if type(user_question) == list:
|
740 |
+
user_question = user_question[0]["text"]
|
741 |
+
filename = replace_special_symbols(user_question)[:16] + ".json"
|
742 |
+
return self.rename_chat_history(filename, chatbot, user_name)
|
743 |
+
else:
|
744 |
+
return gr.update()
|
745 |
|
746 |
def auto_save(self, chatbot):
|
747 |
+
save_file(self.history_file_path, self.system_prompt,
|
|
|
748 |
self.history, chatbot, self.user_identifier)
|
749 |
|
750 |
def export_markdown(self, filename, chatbot, user_name):
|
|
|
752 |
return
|
753 |
if not filename.endswith(".md"):
|
754 |
filename += ".md"
|
755 |
+
save_file(filename, self.system_prompt, self.history, chatbot, user_name)
|
756 |
+
|
757 |
+
def load_chat_history(self, new_history_file_path=None, username=None):
|
758 |
+
logging.debug(f"{self.user_identifier} 加载对话历史中……")
|
759 |
+
if new_history_file_path is not None:
|
760 |
+
if type(new_history_file_path) != str:
|
761 |
+
# copy file from new_history_file_path.name to os.path.join(HISTORY_DIR, self.user_identifier)
|
762 |
+
new_history_file_path = new_history_file_path.name
|
763 |
+
shutil.copyfile(new_history_file_path, os.path.join(
|
764 |
+
HISTORY_DIR, self.user_identifier, os.path.basename(new_history_file_path)))
|
765 |
+
self.history_file_path = os.path.basename(new_history_file_path)
|
766 |
+
else:
|
767 |
+
self.history_file_path = new_history_file_path
|
768 |
try:
|
769 |
+
if self.history_file_path == os.path.basename(self.history_file_path):
|
770 |
history_file_path = os.path.join(
|
771 |
+
HISTORY_DIR, self.user_identifier, self.history_file_path)
|
772 |
else:
|
773 |
+
history_file_path = self.history_file_path
|
774 |
+
if not self.history_file_path.endswith(".json"):
|
775 |
+
history_file_path += ".json"
|
776 |
with open(history_file_path, "r", encoding="utf-8") as f:
|
777 |
json_s = json.load(f)
|
778 |
try:
|
|
|
788 |
logging.info(new_history)
|
789 |
except:
|
790 |
pass
|
791 |
+
if len(json_s["chatbot"]) < len(json_s["history"])//2:
|
792 |
+
logging.info("Trimming corrupted history...")
|
793 |
+
json_s["history"] = json_s["history"][-len(json_s["chatbot"]):]
|
794 |
+
logging.info(f"Trimmed history: {json_s['history']}")
|
795 |
+
logging.debug(f"{self.user_identifier} 加载对话历史完毕")
|
796 |
self.history = json_s["history"]
|
797 |
+
return os.path.basename(self.history_file_path), json_s["system"], json_s["chatbot"]
|
798 |
except:
|
799 |
# 没有对话历史或者对话历史解析失败
|
800 |
+
logging.info(f"没有找到对话历史记录 {self.history_file_path}")
|
801 |
+
return self.history_file_path, "", []
|
802 |
|
803 |
def delete_chat_history(self, filename, user_name):
|
804 |
if filename == "CANCELED":
|
|
|
807 |
return i18n("你没有选择任何对话历史"), gr.update(), gr.update()
|
808 |
if not filename.endswith(".json"):
|
809 |
filename += ".json"
|
810 |
+
if filename == os.path.basename(filename):
|
811 |
history_file_path = os.path.join(HISTORY_DIR, user_name, filename)
|
812 |
else:
|
813 |
history_file_path = filename
|
814 |
+
md_history_file_path = history_file_path[:-5] + ".md"
|
815 |
try:
|
816 |
os.remove(history_file_path)
|
817 |
+
os.remove(md_history_file_path)
|
818 |
+
return i18n("删除对话历史成功"), get_history_list(user_name), []
|
819 |
except:
|
820 |
logging.info(f"删除对话历史失败 {history_file_path}")
|
821 |
+
return i18n("对话历史")+filename+i18n("已经被删除啦"), get_history_list(user_name), []
|
822 |
|
823 |
def auto_load(self):
|
824 |
+
filepath = get_history_filepath(self.user_identifier)
|
825 |
+
if not filepath:
|
826 |
+
self.history_file_path = new_auto_history_filename(
|
827 |
+
self.user_identifier)
|
828 |
+
else:
|
829 |
+
self.history_file_path = filepath
|
830 |
+
filename, system_prompt, chatbot = self.load_chat_history()
|
831 |
+
filename = filename[:-5]
|
832 |
+
return filename, system_prompt, chatbot
|
833 |
|
834 |
def like(self):
|
835 |
"""like the last response, implement if needed
|
modules/models/midjourney.py
CHANGED
@@ -2,11 +2,10 @@ import base64
|
|
2 |
import io
|
3 |
import json
|
4 |
import logging
|
|
|
5 |
import pathlib
|
6 |
-
import time
|
7 |
import tempfile
|
8 |
-
import
|
9 |
-
|
10 |
from datetime import datetime
|
11 |
|
12 |
import requests
|
@@ -14,7 +13,7 @@ import tiktoken
|
|
14 |
from PIL import Image
|
15 |
|
16 |
from modules.config import retrieve_proxy
|
17 |
-
from modules.models.
|
18 |
|
19 |
mj_proxy_api_base = os.getenv("MIDJOURNEY_PROXY_API_BASE")
|
20 |
mj_discord_proxy_url = os.getenv("MIDJOURNEY_DISCORD_PROXY_URL")
|
@@ -218,10 +217,10 @@ class Midjourney_Client(XMChat):
|
|
218 |
logging.info("使用图片作为输入")
|
219 |
return None, chatbot, None
|
220 |
|
221 |
-
def reset(self):
|
222 |
self.image_bytes = None
|
223 |
self.image_path = None
|
224 |
-
return
|
225 |
|
226 |
def get_answer_at_once(self):
|
227 |
content = self.history[-1]['content']
|
@@ -367,7 +366,7 @@ UPSCALE - 确认后放大图片,第一个数值为需要放大的图片(1~4
|
|
367 |
请使用SD进行UPSCALE
|
368 |
VARIATION - 图片变体,第一个数值为需要放大的图片(1~4),第二参数为任务ID
|
369 |
/mj VARIATION::1::123456789
|
370 |
-
|
371 |
【绘图参数】
|
372 |
所有命令默认会带上参数--v 5.2
|
373 |
其他参数参照 https://docs.midjourney.com/docs/parameter-list
|
|
|
2 |
import io
|
3 |
import json
|
4 |
import logging
|
5 |
+
import os
|
6 |
import pathlib
|
|
|
7 |
import tempfile
|
8 |
+
import time
|
|
|
9 |
from datetime import datetime
|
10 |
|
11 |
import requests
|
|
|
13 |
from PIL import Image
|
14 |
|
15 |
from modules.config import retrieve_proxy
|
16 |
+
from modules.models.XMChat import XMChat
|
17 |
|
18 |
mj_proxy_api_base = os.getenv("MIDJOURNEY_PROXY_API_BASE")
|
19 |
mj_discord_proxy_url = os.getenv("MIDJOURNEY_DISCORD_PROXY_URL")
|
|
|
217 |
logging.info("使用图片作为输入")
|
218 |
return None, chatbot, None
|
219 |
|
220 |
+
def reset(self, remain_system_prompt=False):
|
221 |
self.image_bytes = None
|
222 |
self.image_path = None
|
223 |
+
return super().reset()
|
224 |
|
225 |
def get_answer_at_once(self):
|
226 |
content = self.history[-1]['content']
|
|
|
366 |
请使用SD进行UPSCALE
|
367 |
VARIATION - 图片变体,第一个数值为需要放大的图片(1~4),第二参数为任务ID
|
368 |
/mj VARIATION::1::123456789
|
369 |
+
|
370 |
【绘图参数】
|
371 |
所有命令默认会带上参数--v 5.2
|
372 |
其他参数参照 https://docs.midjourney.com/docs/parameter-list
|
modules/models/models.py
CHANGED
@@ -1,546 +1,19 @@
|
|
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 |
-
import
|
19 |
-
|
20 |
-
from
|
21 |
-
import uuid
|
22 |
|
23 |
-
from ..presets import *
|
24 |
from ..index_func import *
|
|
|
25 |
from ..utils import *
|
26 |
-
from .. import shared
|
27 |
-
from ..config import retrieve_proxy, usage_limit, sensitive_id
|
28 |
-
from modules import config
|
29 |
from .base_model import BaseLLMModel, ModelType
|
30 |
|
31 |
|
32 |
-
class OpenAIClient(BaseLLMModel):
|
33 |
-
def __init__(
|
34 |
-
self,
|
35 |
-
model_name,
|
36 |
-
api_key,
|
37 |
-
system_prompt=INITIAL_SYSTEM_PROMPT,
|
38 |
-
temperature=1.0,
|
39 |
-
top_p=1.0,
|
40 |
-
user_name=""
|
41 |
-
) -> None:
|
42 |
-
super().__init__(
|
43 |
-
model_name=model_name,
|
44 |
-
temperature=temperature,
|
45 |
-
top_p=top_p,
|
46 |
-
system_prompt=system_prompt,
|
47 |
-
user=user_name
|
48 |
-
)
|
49 |
-
self.api_key = api_key
|
50 |
-
self.need_api_key = True
|
51 |
-
self._refresh_header()
|
52 |
-
|
53 |
-
def get_answer_stream_iter(self):
|
54 |
-
response = self._get_response(stream=True)
|
55 |
-
if response is not None:
|
56 |
-
iter = self._decode_chat_response(response)
|
57 |
-
partial_text = ""
|
58 |
-
for i in iter:
|
59 |
-
partial_text += i
|
60 |
-
yield partial_text
|
61 |
-
else:
|
62 |
-
yield STANDARD_ERROR_MSG + GENERAL_ERROR_MSG
|
63 |
-
|
64 |
-
def get_answer_at_once(self):
|
65 |
-
response = self._get_response()
|
66 |
-
response = json.loads(response.text)
|
67 |
-
content = response["choices"][0]["message"]["content"]
|
68 |
-
total_token_count = response["usage"]["total_tokens"]
|
69 |
-
return content, total_token_count
|
70 |
-
|
71 |
-
def count_token(self, user_input):
|
72 |
-
input_token_count = count_token(construct_user(user_input))
|
73 |
-
if self.system_prompt is not None and len(self.all_token_counts) == 0:
|
74 |
-
system_prompt_token_count = count_token(
|
75 |
-
construct_system(self.system_prompt)
|
76 |
-
)
|
77 |
-
return input_token_count + system_prompt_token_count
|
78 |
-
return input_token_count
|
79 |
-
|
80 |
-
def billing_info(self):
|
81 |
-
try:
|
82 |
-
curr_time = datetime.datetime.now()
|
83 |
-
last_day_of_month = get_last_day_of_month(
|
84 |
-
curr_time).strftime("%Y-%m-%d")
|
85 |
-
first_day_of_month = curr_time.replace(day=1).strftime("%Y-%m-%d")
|
86 |
-
usage_url = f"{shared.state.usage_api_url}?start_date={first_day_of_month}&end_date={last_day_of_month}"
|
87 |
-
try:
|
88 |
-
usage_data = self._get_billing_data(usage_url)
|
89 |
-
except Exception as e:
|
90 |
-
# logging.error(f"获取API使用情况失败: " + str(e))
|
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 |
-
from ..webui import get_html
|
100 |
-
# return i18n("**本月使用金额** ") + f"\u3000 ${rounded_usage}"
|
101 |
-
return get_html("billing_info.html").format(
|
102 |
-
label = i18n("本月使用金额"),
|
103 |
-
usage_percent = usage_percent,
|
104 |
-
rounded_usage = rounded_usage,
|
105 |
-
usage_limit = usage_limit
|
106 |
-
)
|
107 |
-
except requests.exceptions.ConnectTimeout:
|
108 |
-
status_text = (
|
109 |
-
STANDARD_ERROR_MSG + CONNECTION_TIMEOUT_MSG + ERROR_RETRIEVE_MSG
|
110 |
-
)
|
111 |
-
return status_text
|
112 |
-
except requests.exceptions.ReadTimeout:
|
113 |
-
status_text = STANDARD_ERROR_MSG + READ_TIMEOUT_MSG + ERROR_RETRIEVE_MSG
|
114 |
-
return status_text
|
115 |
-
except Exception as e:
|
116 |
-
import traceback
|
117 |
-
traceback.print_exc()
|
118 |
-
logging.error(i18n("获取API使用情况失败:") + str(e))
|
119 |
-
return STANDARD_ERROR_MSG + ERROR_RETRIEVE_MSG
|
120 |
-
|
121 |
-
def set_token_upper_limit(self, new_upper_limit):
|
122 |
-
pass
|
123 |
-
|
124 |
-
@shared.state.switching_api_key # 在不开启多账号模式的时候,这个装饰器不会起作用
|
125 |
-
def _get_response(self, stream=False):
|
126 |
-
openai_api_key = self.api_key
|
127 |
-
system_prompt = self.system_prompt
|
128 |
-
history = self.history
|
129 |
-
logging.debug(colorama.Fore.YELLOW +
|
130 |
-
f"{history}" + colorama.Fore.RESET)
|
131 |
-
headers = {
|
132 |
-
"Content-Type": "application/json",
|
133 |
-
"Authorization": f"Bearer {openai_api_key}",
|
134 |
-
}
|
135 |
-
|
136 |
-
if system_prompt is not None:
|
137 |
-
history = [construct_system(system_prompt), *history]
|
138 |
-
|
139 |
-
payload = {
|
140 |
-
"model": self.model_name,
|
141 |
-
"messages": history,
|
142 |
-
"temperature": self.temperature,
|
143 |
-
"top_p": self.top_p,
|
144 |
-
"n": self.n_choices,
|
145 |
-
"stream": stream,
|
146 |
-
"presence_penalty": self.presence_penalty,
|
147 |
-
"frequency_penalty": self.frequency_penalty,
|
148 |
-
}
|
149 |
-
|
150 |
-
if self.max_generation_token is not None:
|
151 |
-
payload["max_tokens"] = self.max_generation_token
|
152 |
-
if self.stop_sequence is not None:
|
153 |
-
payload["stop"] = self.stop_sequence
|
154 |
-
if self.logit_bias is not None:
|
155 |
-
payload["logit_bias"] = self.logit_bias
|
156 |
-
if self.user_identifier:
|
157 |
-
payload["user"] = self.user_identifier
|
158 |
-
|
159 |
-
if stream:
|
160 |
-
timeout = TIMEOUT_STREAMING
|
161 |
-
else:
|
162 |
-
timeout = TIMEOUT_ALL
|
163 |
-
|
164 |
-
# 如果有自定义的api-host,使用自定义host发送请求,否则使用默认设置发送请求
|
165 |
-
if shared.state.completion_url != COMPLETION_URL:
|
166 |
-
logging.debug(f"使用自定义API URL: {shared.state.completion_url}")
|
167 |
-
|
168 |
-
with retrieve_proxy():
|
169 |
-
try:
|
170 |
-
response = requests.post(
|
171 |
-
shared.state.completion_url,
|
172 |
-
headers=headers,
|
173 |
-
json=payload,
|
174 |
-
stream=stream,
|
175 |
-
timeout=timeout,
|
176 |
-
)
|
177 |
-
except:
|
178 |
-
return None
|
179 |
-
return response
|
180 |
-
|
181 |
-
def _refresh_header(self):
|
182 |
-
self.headers = {
|
183 |
-
"Content-Type": "application/json",
|
184 |
-
"Authorization": f"Bearer {sensitive_id}",
|
185 |
-
}
|
186 |
-
|
187 |
-
|
188 |
-
def _get_billing_data(self, billing_url):
|
189 |
-
with retrieve_proxy():
|
190 |
-
response = requests.get(
|
191 |
-
billing_url,
|
192 |
-
headers=self.headers,
|
193 |
-
timeout=TIMEOUT_ALL,
|
194 |
-
)
|
195 |
-
|
196 |
-
if response.status_code == 200:
|
197 |
-
data = response.json()
|
198 |
-
return data
|
199 |
-
else:
|
200 |
-
raise Exception(
|
201 |
-
f"API request failed with status code {response.status_code}: {response.text}"
|
202 |
-
)
|
203 |
-
|
204 |
-
def _decode_chat_response(self, response):
|
205 |
-
error_msg = ""
|
206 |
-
for chunk in response.iter_lines():
|
207 |
-
if chunk:
|
208 |
-
chunk = chunk.decode()
|
209 |
-
chunk_length = len(chunk)
|
210 |
-
try:
|
211 |
-
chunk = json.loads(chunk[6:])
|
212 |
-
except:
|
213 |
-
print(i18n("JSON解析错误,收到的内容: ") + f"{chunk}")
|
214 |
-
error_msg += chunk
|
215 |
-
continue
|
216 |
-
if chunk_length > 6 and "delta" in chunk["choices"][0]:
|
217 |
-
if chunk["choices"][0]["finish_reason"] == "stop":
|
218 |
-
break
|
219 |
-
try:
|
220 |
-
yield chunk["choices"][0]["delta"]["content"]
|
221 |
-
except Exception as e:
|
222 |
-
# logging.error(f"Error: {e}")
|
223 |
-
continue
|
224 |
-
if error_msg:
|
225 |
-
raise Exception(error_msg)
|
226 |
-
|
227 |
-
def set_key(self, new_access_key):
|
228 |
-
ret = super().set_key(new_access_key)
|
229 |
-
self._refresh_header()
|
230 |
-
return ret
|
231 |
-
|
232 |
-
|
233 |
-
class ChatGLM_Client(BaseLLMModel):
|
234 |
-
def __init__(self, model_name, user_name="") -> None:
|
235 |
-
super().__init__(model_name=model_name, user=user_name)
|
236 |
-
from transformers import AutoTokenizer, AutoModel
|
237 |
-
import torch
|
238 |
-
global CHATGLM_TOKENIZER, CHATGLM_MODEL
|
239 |
-
if CHATGLM_TOKENIZER is None or CHATGLM_MODEL is None:
|
240 |
-
system_name = platform.system()
|
241 |
-
model_path = None
|
242 |
-
if os.path.exists("models"):
|
243 |
-
model_dirs = os.listdir("models")
|
244 |
-
if model_name in model_dirs:
|
245 |
-
model_path = f"models/{model_name}"
|
246 |
-
if model_path is not None:
|
247 |
-
model_source = model_path
|
248 |
-
else:
|
249 |
-
model_source = f"THUDM/{model_name}"
|
250 |
-
CHATGLM_TOKENIZER = AutoTokenizer.from_pretrained(
|
251 |
-
model_source, trust_remote_code=True
|
252 |
-
)
|
253 |
-
quantified = False
|
254 |
-
if "int4" in model_name:
|
255 |
-
quantified = True
|
256 |
-
model = AutoModel.from_pretrained(
|
257 |
-
model_source, trust_remote_code=True
|
258 |
-
)
|
259 |
-
if torch.cuda.is_available():
|
260 |
-
# run on CUDA
|
261 |
-
logging.info("CUDA is available, using CUDA")
|
262 |
-
model = model.half().cuda()
|
263 |
-
# mps加速还存在一些问题,暂时不使用
|
264 |
-
elif system_name == "Darwin" and model_path is not None and not quantified:
|
265 |
-
logging.info("Running on macOS, using MPS")
|
266 |
-
# running on macOS and model already downloaded
|
267 |
-
model = model.half().to("mps")
|
268 |
-
else:
|
269 |
-
logging.info("GPU is not available, using CPU")
|
270 |
-
model = model.float()
|
271 |
-
model = model.eval()
|
272 |
-
CHATGLM_MODEL = model
|
273 |
-
|
274 |
-
def _get_glm_style_input(self):
|
275 |
-
history = [x["content"] for x in self.history]
|
276 |
-
query = history.pop()
|
277 |
-
logging.debug(colorama.Fore.YELLOW +
|
278 |
-
f"{history}" + colorama.Fore.RESET)
|
279 |
-
assert (
|
280 |
-
len(history) % 2 == 0
|
281 |
-
), f"History should be even length. current history is: {history}"
|
282 |
-
history = [[history[i], history[i + 1]]
|
283 |
-
for i in range(0, len(history), 2)]
|
284 |
-
return history, query
|
285 |
-
|
286 |
-
def get_answer_at_once(self):
|
287 |
-
history, query = self._get_glm_style_input()
|
288 |
-
response, _ = CHATGLM_MODEL.chat(
|
289 |
-
CHATGLM_TOKENIZER, query, history=history)
|
290 |
-
return response, len(response)
|
291 |
-
|
292 |
-
def get_answer_stream_iter(self):
|
293 |
-
history, query = self._get_glm_style_input()
|
294 |
-
for response, history in CHATGLM_MODEL.stream_chat(
|
295 |
-
CHATGLM_TOKENIZER,
|
296 |
-
query,
|
297 |
-
history,
|
298 |
-
max_length=self.token_upper_limit,
|
299 |
-
top_p=self.top_p,
|
300 |
-
temperature=self.temperature,
|
301 |
-
):
|
302 |
-
yield response
|
303 |
-
|
304 |
-
|
305 |
-
class LLaMA_Client(BaseLLMModel):
|
306 |
-
def __init__(
|
307 |
-
self,
|
308 |
-
model_name,
|
309 |
-
lora_path=None,
|
310 |
-
user_name=""
|
311 |
-
) -> None:
|
312 |
-
super().__init__(model_name=model_name, user=user_name)
|
313 |
-
from lmflow.datasets.dataset import Dataset
|
314 |
-
from lmflow.pipeline.auto_pipeline import AutoPipeline
|
315 |
-
from lmflow.models.auto_model import AutoModel
|
316 |
-
from lmflow.args import ModelArguments, DatasetArguments, InferencerArguments
|
317 |
-
|
318 |
-
self.max_generation_token = 1000
|
319 |
-
self.end_string = "\n\n"
|
320 |
-
# We don't need input data
|
321 |
-
data_args = DatasetArguments(dataset_path=None)
|
322 |
-
self.dataset = Dataset(data_args)
|
323 |
-
self.system_prompt = ""
|
324 |
-
|
325 |
-
global LLAMA_MODEL, LLAMA_INFERENCER
|
326 |
-
if LLAMA_MODEL is None or LLAMA_INFERENCER is None:
|
327 |
-
model_path = None
|
328 |
-
if os.path.exists("models"):
|
329 |
-
model_dirs = os.listdir("models")
|
330 |
-
if model_name in model_dirs:
|
331 |
-
model_path = f"models/{model_name}"
|
332 |
-
if model_path is not None:
|
333 |
-
model_source = model_path
|
334 |
-
else:
|
335 |
-
model_source = f"decapoda-research/{model_name}"
|
336 |
-
# raise Exception(f"models目录下没有这个模型: {model_name}")
|
337 |
-
if lora_path is not None:
|
338 |
-
lora_path = f"lora/{lora_path}"
|
339 |
-
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,
|
340 |
-
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)
|
341 |
-
pipeline_args = InferencerArguments(
|
342 |
-
local_rank=0, random_seed=1, deepspeed='configs/ds_config_chatbot.json', mixed_precision='bf16')
|
343 |
-
|
344 |
-
with open(pipeline_args.deepspeed, "r", encoding="utf-8") as f:
|
345 |
-
ds_config = json.load(f)
|
346 |
-
LLAMA_MODEL = AutoModel.get_model(
|
347 |
-
model_args,
|
348 |
-
tune_strategy="none",
|
349 |
-
ds_config=ds_config,
|
350 |
-
)
|
351 |
-
LLAMA_INFERENCER = AutoPipeline.get_pipeline(
|
352 |
-
pipeline_name="inferencer",
|
353 |
-
model_args=model_args,
|
354 |
-
data_args=data_args,
|
355 |
-
pipeline_args=pipeline_args,
|
356 |
-
)
|
357 |
-
|
358 |
-
def _get_llama_style_input(self):
|
359 |
-
history = []
|
360 |
-
instruction = ""
|
361 |
-
if self.system_prompt:
|
362 |
-
instruction = (f"Instruction: {self.system_prompt}\n")
|
363 |
-
for x in self.history:
|
364 |
-
if x["role"] == "user":
|
365 |
-
history.append(f"{instruction}Input: {x['content']}")
|
366 |
-
else:
|
367 |
-
history.append(f"Output: {x['content']}")
|
368 |
-
context = "\n\n".join(history)
|
369 |
-
context += "\n\nOutput: "
|
370 |
-
return context
|
371 |
-
|
372 |
-
def get_answer_at_once(self):
|
373 |
-
context = self._get_llama_style_input()
|
374 |
-
|
375 |
-
input_dataset = self.dataset.from_dict(
|
376 |
-
{"type": "text_only", "instances": [{"text": context}]}
|
377 |
-
)
|
378 |
-
|
379 |
-
output_dataset = LLAMA_INFERENCER.inference(
|
380 |
-
model=LLAMA_MODEL,
|
381 |
-
dataset=input_dataset,
|
382 |
-
max_new_tokens=self.max_generation_token,
|
383 |
-
temperature=self.temperature,
|
384 |
-
)
|
385 |
-
|
386 |
-
response = output_dataset.to_dict()["instances"][0]["text"]
|
387 |
-
return response, len(response)
|
388 |
-
|
389 |
-
def get_answer_stream_iter(self):
|
390 |
-
context = self._get_llama_style_input()
|
391 |
-
partial_text = ""
|
392 |
-
step = 1
|
393 |
-
for _ in range(0, self.max_generation_token, step):
|
394 |
-
input_dataset = self.dataset.from_dict(
|
395 |
-
{"type": "text_only", "instances": [
|
396 |
-
{"text": context + partial_text}]}
|
397 |
-
)
|
398 |
-
output_dataset = LLAMA_INFERENCER.inference(
|
399 |
-
model=LLAMA_MODEL,
|
400 |
-
dataset=input_dataset,
|
401 |
-
max_new_tokens=step,
|
402 |
-
temperature=self.temperature,
|
403 |
-
)
|
404 |
-
response = output_dataset.to_dict()["instances"][0]["text"]
|
405 |
-
if response == "" or response == self.end_string:
|
406 |
-
break
|
407 |
-
partial_text += response
|
408 |
-
yield partial_text
|
409 |
-
|
410 |
-
|
411 |
-
class XMChat(BaseLLMModel):
|
412 |
-
def __init__(self, api_key, user_name=""):
|
413 |
-
super().__init__(model_name="xmchat", user=user_name)
|
414 |
-
self.api_key = api_key
|
415 |
-
self.session_id = None
|
416 |
-
self.reset()
|
417 |
-
self.image_bytes = None
|
418 |
-
self.image_path = None
|
419 |
-
self.xm_history = []
|
420 |
-
self.url = "https://xmbot.net/web"
|
421 |
-
self.last_conv_id = None
|
422 |
-
|
423 |
-
def reset(self):
|
424 |
-
self.session_id = str(uuid.uuid4())
|
425 |
-
self.last_conv_id = None
|
426 |
-
return [], "已重置"
|
427 |
-
|
428 |
-
def image_to_base64(self, image_path):
|
429 |
-
# 打开并加载图片
|
430 |
-
img = Image.open(image_path)
|
431 |
-
|
432 |
-
# 获取图片的宽度和高度
|
433 |
-
width, height = img.size
|
434 |
-
|
435 |
-
# 计算压缩比例,以确保最长边小于4096像素
|
436 |
-
max_dimension = 2048
|
437 |
-
scale_ratio = min(max_dimension / width, max_dimension / height)
|
438 |
-
|
439 |
-
if scale_ratio < 1:
|
440 |
-
# 按压缩比例调整图片大小
|
441 |
-
new_width = int(width * scale_ratio)
|
442 |
-
new_height = int(height * scale_ratio)
|
443 |
-
img = img.resize((new_width, new_height), Image.ANTIALIAS)
|
444 |
-
|
445 |
-
# 将图片转换为jpg格式的二进制数据
|
446 |
-
buffer = BytesIO()
|
447 |
-
if img.mode == "RGBA":
|
448 |
-
img = img.convert("RGB")
|
449 |
-
img.save(buffer, format='JPEG')
|
450 |
-
binary_image = buffer.getvalue()
|
451 |
-
|
452 |
-
# 对二进制数据进行Base64编码
|
453 |
-
base64_image = base64.b64encode(binary_image).decode('utf-8')
|
454 |
-
|
455 |
-
return base64_image
|
456 |
-
|
457 |
-
def try_read_image(self, filepath):
|
458 |
-
def is_image_file(filepath):
|
459 |
-
# 判断文件是否为图片
|
460 |
-
valid_image_extensions = [
|
461 |
-
".jpg", ".jpeg", ".png", ".bmp", ".gif", ".tiff"]
|
462 |
-
file_extension = os.path.splitext(filepath)[1].lower()
|
463 |
-
return file_extension in valid_image_extensions
|
464 |
-
|
465 |
-
if is_image_file(filepath):
|
466 |
-
logging.info(f"读取图片文件: {filepath}")
|
467 |
-
self.image_bytes = self.image_to_base64(filepath)
|
468 |
-
self.image_path = filepath
|
469 |
-
else:
|
470 |
-
self.image_bytes = None
|
471 |
-
self.image_path = None
|
472 |
-
|
473 |
-
def like(self):
|
474 |
-
if self.last_conv_id is None:
|
475 |
-
return "点赞失败,你还没发送过消息"
|
476 |
-
data = {
|
477 |
-
"uuid": self.last_conv_id,
|
478 |
-
"appraise": "good"
|
479 |
-
}
|
480 |
-
requests.post(self.url, json=data)
|
481 |
-
return "👍点赞成功,感谢反馈~"
|
482 |
-
|
483 |
-
def dislike(self):
|
484 |
-
if self.last_conv_id is None:
|
485 |
-
return "点踩失败,你还没发送过消息"
|
486 |
-
data = {
|
487 |
-
"uuid": self.last_conv_id,
|
488 |
-
"appraise": "bad"
|
489 |
-
}
|
490 |
-
requests.post(self.url, json=data)
|
491 |
-
return "👎点踩成功,感谢反馈~"
|
492 |
-
|
493 |
-
def prepare_inputs(self, real_inputs, use_websearch, files, reply_language, chatbot):
|
494 |
-
fake_inputs = real_inputs
|
495 |
-
display_append = ""
|
496 |
-
limited_context = False
|
497 |
-
return limited_context, fake_inputs, display_append, real_inputs, chatbot
|
498 |
-
|
499 |
-
def handle_file_upload(self, files, chatbot, language):
|
500 |
-
"""if the model accepts multi modal input, implement this function"""
|
501 |
-
if files:
|
502 |
-
for file in files:
|
503 |
-
if file.name:
|
504 |
-
logging.info(f"尝试读取图像: {file.name}")
|
505 |
-
self.try_read_image(file.name)
|
506 |
-
if self.image_path is not None:
|
507 |
-
chatbot = chatbot + [((self.image_path,), None)]
|
508 |
-
if self.image_bytes is not None:
|
509 |
-
logging.info("使用图片作为输入")
|
510 |
-
# XMChat的一轮对话中实际上只能处理一张图片
|
511 |
-
self.reset()
|
512 |
-
conv_id = str(uuid.uuid4())
|
513 |
-
data = {
|
514 |
-
"user_id": self.api_key,
|
515 |
-
"session_id": self.session_id,
|
516 |
-
"uuid": conv_id,
|
517 |
-
"data_type": "imgbase64",
|
518 |
-
"data": self.image_bytes
|
519 |
-
}
|
520 |
-
response = requests.post(self.url, json=data)
|
521 |
-
response = json.loads(response.text)
|
522 |
-
logging.info(f"图片回复: {response['data']}")
|
523 |
-
return None, chatbot, None
|
524 |
-
|
525 |
-
def get_answer_at_once(self):
|
526 |
-
question = self.history[-1]["content"]
|
527 |
-
conv_id = str(uuid.uuid4())
|
528 |
-
self.last_conv_id = conv_id
|
529 |
-
data = {
|
530 |
-
"user_id": self.api_key,
|
531 |
-
"session_id": self.session_id,
|
532 |
-
"uuid": conv_id,
|
533 |
-
"data_type": "text",
|
534 |
-
"data": question
|
535 |
-
}
|
536 |
-
response = requests.post(self.url, json=data)
|
537 |
-
try:
|
538 |
-
response = json.loads(response.text)
|
539 |
-
return response["data"], len(response["data"])
|
540 |
-
except Exception as e:
|
541 |
-
return response.text, len(response.text)
|
542 |
-
|
543 |
-
|
544 |
def get_model(
|
545 |
model_name,
|
546 |
lora_model_path=None,
|
@@ -548,21 +21,23 @@ def get_model(
|
|
548 |
temperature=None,
|
549 |
top_p=None,
|
550 |
system_prompt=None,
|
551 |
-
user_name=""
|
|
|
552 |
) -> BaseLLMModel:
|
553 |
msg = i18n("模型设置为了:") + f" {model_name}"
|
554 |
model_type = ModelType.get_type(model_name)
|
555 |
lora_selector_visibility = False
|
556 |
-
lora_choices = []
|
557 |
dont_change_lora_selector = False
|
558 |
if model_type != ModelType.OpenAI:
|
559 |
config.local_embedding = True
|
560 |
# del current_model.model
|
561 |
-
model =
|
562 |
chatbot = gr.Chatbot.update(label=model_name)
|
563 |
try:
|
564 |
if model_type == ModelType.OpenAI:
|
565 |
logging.info(f"正在加载OpenAI模型: {model_name}")
|
|
|
566 |
access_key = os.environ.get("OPENAI_API_KEY", access_key)
|
567 |
model = OpenAIClient(
|
568 |
model_name=model_name,
|
@@ -572,19 +47,31 @@ def get_model(
|
|
572 |
top_p=top_p,
|
573 |
user_name=user_name,
|
574 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
575 |
elif model_type == ModelType.ChatGLM:
|
576 |
logging.info(f"正在加载ChatGLM模型: {model_name}")
|
|
|
577 |
model = ChatGLM_Client(model_name, user_name=user_name)
|
578 |
elif model_type == ModelType.LLaMA and lora_model_path == "":
|
579 |
msg = f"现在请为 {model_name} 选择LoRA模型"
|
580 |
logging.info(msg)
|
581 |
lora_selector_visibility = True
|
582 |
if os.path.isdir("lora"):
|
583 |
-
lora_choices =
|
584 |
-
"lora", plain=True, filetypes=[""])
|
585 |
-
lora_choices = ["No LoRA"] + lora_choices
|
586 |
elif model_type == ModelType.LLaMA and lora_model_path != "":
|
587 |
logging.info(f"正在加载LLaMA模型: {model_name} + {lora_model_path}")
|
|
|
588 |
dont_change_lora_selector = True
|
589 |
if lora_model_path == "No LoRA":
|
590 |
lora_model_path = None
|
@@ -594,6 +81,7 @@ def get_model(
|
|
594 |
model = LLaMA_Client(
|
595 |
model_name, lora_model_path, user_name=user_name)
|
596 |
elif model_type == ModelType.XMChat:
|
|
|
597 |
if os.environ.get("XMCHAT_API_KEY") != "":
|
598 |
access_key = os.environ.get("XMCHAT_API_KEY")
|
599 |
model = XMChat(api_key=access_key, user_name=user_name)
|
@@ -605,26 +93,41 @@ def get_model(
|
|
605 |
model = MOSS_Client(model_name, user_name=user_name)
|
606 |
elif model_type == ModelType.YuanAI:
|
607 |
from .inspurai import Yuan_Client
|
608 |
-
model = Yuan_Client(model_name, api_key=access_key,
|
|
|
609 |
elif model_type == ModelType.Minimax:
|
610 |
from .minimax import MiniMax_Client
|
611 |
if os.environ.get("MINIMAX_API_KEY") != "":
|
612 |
access_key = os.environ.get("MINIMAX_API_KEY")
|
613 |
-
model = MiniMax_Client(
|
|
|
614 |
elif model_type == ModelType.ChuanhuAgent:
|
615 |
from .ChuanhuAgent import ChuanhuAgent_Client
|
616 |
model = ChuanhuAgent_Client(model_name, access_key, user_name=user_name)
|
|
|
617 |
elif model_type == ModelType.GooglePaLM:
|
618 |
-
from .
|
619 |
access_key = os.environ.get("GOOGLE_PALM_API_KEY", access_key)
|
620 |
-
model = Google_PaLM_Client(
|
|
|
621 |
elif model_type == ModelType.LangchainChat:
|
622 |
-
from .
|
623 |
model = Azure_OpenAI_Client(model_name, user_name=user_name)
|
624 |
elif model_type == ModelType.Midjourney:
|
625 |
from .midjourney import Midjourney_Client
|
626 |
mj_proxy_api_secret = os.getenv("MIDJOURNEY_PROXY_API_SECRET")
|
627 |
-
model = Midjourney_Client(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
628 |
elif model_type == ModelType.Unknown:
|
629 |
raise ValueError(f"未知模型: {model_name}")
|
630 |
logging.info(msg)
|
@@ -633,6 +136,9 @@ def get_model(
|
|
633 |
traceback.print_exc()
|
634 |
msg = f"{STANDARD_ERROR_MSG}: {e}"
|
635 |
presudo_key = hide_middle_chars(access_key)
|
|
|
|
|
|
|
636 |
if dont_change_lora_selector:
|
637 |
return model, msg, chatbot, gr.update(), access_key, presudo_key
|
638 |
else:
|
|
|
1 |
from __future__ import annotations
|
|
|
2 |
|
3 |
import logging
|
|
|
|
|
4 |
import os
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
|
|
6 |
import colorama
|
7 |
+
import commentjson as cjson
|
8 |
+
|
9 |
+
from modules import config
|
|
|
10 |
|
|
|
11 |
from ..index_func import *
|
12 |
+
from ..presets import *
|
13 |
from ..utils import *
|
|
|
|
|
|
|
14 |
from .base_model import BaseLLMModel, ModelType
|
15 |
|
16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
def get_model(
|
18 |
model_name,
|
19 |
lora_model_path=None,
|
|
|
21 |
temperature=None,
|
22 |
top_p=None,
|
23 |
system_prompt=None,
|
24 |
+
user_name="",
|
25 |
+
original_model = None
|
26 |
) -> BaseLLMModel:
|
27 |
msg = i18n("模型设置为了:") + f" {model_name}"
|
28 |
model_type = ModelType.get_type(model_name)
|
29 |
lora_selector_visibility = False
|
30 |
+
lora_choices = ["No LoRA"]
|
31 |
dont_change_lora_selector = False
|
32 |
if model_type != ModelType.OpenAI:
|
33 |
config.local_embedding = True
|
34 |
# del current_model.model
|
35 |
+
model = original_model
|
36 |
chatbot = gr.Chatbot.update(label=model_name)
|
37 |
try:
|
38 |
if model_type == ModelType.OpenAI:
|
39 |
logging.info(f"正在加载OpenAI模型: {model_name}")
|
40 |
+
from .OpenAI import OpenAIClient
|
41 |
access_key = os.environ.get("OPENAI_API_KEY", access_key)
|
42 |
model = OpenAIClient(
|
43 |
model_name=model_name,
|
|
|
47 |
top_p=top_p,
|
48 |
user_name=user_name,
|
49 |
)
|
50 |
+
elif model_type == ModelType.OpenAIInstruct:
|
51 |
+
logging.info(f"正在加载OpenAI Instruct模型: {model_name}")
|
52 |
+
from .OpenAIInstruct import OpenAI_Instruct_Client
|
53 |
+
access_key = os.environ.get("OPENAI_API_KEY", access_key)
|
54 |
+
model = OpenAI_Instruct_Client(
|
55 |
+
model_name, api_key=access_key, user_name=user_name)
|
56 |
+
elif model_type == ModelType.OpenAIVision:
|
57 |
+
logging.info(f"正在加载OpenAI Vision模型: {model_name}")
|
58 |
+
from .OpenAIVision import OpenAIVisionClient
|
59 |
+
access_key = os.environ.get("OPENAI_API_KEY", access_key)
|
60 |
+
model = OpenAIVisionClient(
|
61 |
+
model_name, api_key=access_key, user_name=user_name)
|
62 |
elif model_type == ModelType.ChatGLM:
|
63 |
logging.info(f"正在加载ChatGLM模型: {model_name}")
|
64 |
+
from .ChatGLM import ChatGLM_Client
|
65 |
model = ChatGLM_Client(model_name, user_name=user_name)
|
66 |
elif model_type == ModelType.LLaMA and lora_model_path == "":
|
67 |
msg = f"现在请为 {model_name} 选择LoRA模型"
|
68 |
logging.info(msg)
|
69 |
lora_selector_visibility = True
|
70 |
if os.path.isdir("lora"):
|
71 |
+
lora_choices = ["No LoRA"] + get_file_names_by_pinyin("lora", filetypes=[""])
|
|
|
|
|
72 |
elif model_type == ModelType.LLaMA and lora_model_path != "":
|
73 |
logging.info(f"正在加载LLaMA模型: {model_name} + {lora_model_path}")
|
74 |
+
from .LLaMA import LLaMA_Client
|
75 |
dont_change_lora_selector = True
|
76 |
if lora_model_path == "No LoRA":
|
77 |
lora_model_path = None
|
|
|
81 |
model = LLaMA_Client(
|
82 |
model_name, lora_model_path, user_name=user_name)
|
83 |
elif model_type == ModelType.XMChat:
|
84 |
+
from .XMChat import XMChat
|
85 |
if os.environ.get("XMCHAT_API_KEY") != "":
|
86 |
access_key = os.environ.get("XMCHAT_API_KEY")
|
87 |
model = XMChat(api_key=access_key, user_name=user_name)
|
|
|
93 |
model = MOSS_Client(model_name, user_name=user_name)
|
94 |
elif model_type == ModelType.YuanAI:
|
95 |
from .inspurai import Yuan_Client
|
96 |
+
model = Yuan_Client(model_name, api_key=access_key,
|
97 |
+
user_name=user_name, system_prompt=system_prompt)
|
98 |
elif model_type == ModelType.Minimax:
|
99 |
from .minimax import MiniMax_Client
|
100 |
if os.environ.get("MINIMAX_API_KEY") != "":
|
101 |
access_key = os.environ.get("MINIMAX_API_KEY")
|
102 |
+
model = MiniMax_Client(
|
103 |
+
model_name, api_key=access_key, user_name=user_name, system_prompt=system_prompt)
|
104 |
elif model_type == ModelType.ChuanhuAgent:
|
105 |
from .ChuanhuAgent import ChuanhuAgent_Client
|
106 |
model = ChuanhuAgent_Client(model_name, access_key, user_name=user_name)
|
107 |
+
msg = i18n("启用的工具:") + ", ".join([i.name for i in model.tools])
|
108 |
elif model_type == ModelType.GooglePaLM:
|
109 |
+
from .GooglePaLM import Google_PaLM_Client
|
110 |
access_key = os.environ.get("GOOGLE_PALM_API_KEY", access_key)
|
111 |
+
model = Google_PaLM_Client(
|
112 |
+
model_name, access_key, user_name=user_name)
|
113 |
elif model_type == ModelType.LangchainChat:
|
114 |
+
from .Azure import Azure_OpenAI_Client
|
115 |
model = Azure_OpenAI_Client(model_name, user_name=user_name)
|
116 |
elif model_type == ModelType.Midjourney:
|
117 |
from .midjourney import Midjourney_Client
|
118 |
mj_proxy_api_secret = os.getenv("MIDJOURNEY_PROXY_API_SECRET")
|
119 |
+
model = Midjourney_Client(
|
120 |
+
model_name, mj_proxy_api_secret, user_name=user_name)
|
121 |
+
elif model_type == ModelType.Spark:
|
122 |
+
from .spark import Spark_Client
|
123 |
+
model = Spark_Client(model_name, os.getenv("SPARK_APPID"), os.getenv(
|
124 |
+
"SPARK_API_KEY"), os.getenv("SPARK_API_SECRET"), user_name=user_name)
|
125 |
+
elif model_type == ModelType.Claude:
|
126 |
+
from .Claude import Claude_Client
|
127 |
+
model = Claude_Client(model_name="claude-2", api_secret=os.getenv("CLAUDE_API_SECRET"))
|
128 |
+
elif model_type == ModelType.Qwen:
|
129 |
+
from .Qwen import Qwen_Client
|
130 |
+
model = Qwen_Client(model_name, user_name=user_name)
|
131 |
elif model_type == ModelType.Unknown:
|
132 |
raise ValueError(f"未知模型: {model_name}")
|
133 |
logging.info(msg)
|
|
|
136 |
traceback.print_exc()
|
137 |
msg = f"{STANDARD_ERROR_MSG}: {e}"
|
138 |
presudo_key = hide_middle_chars(access_key)
|
139 |
+
if original_model is not None and model is not None:
|
140 |
+
model.history = original_model.history
|
141 |
+
model.history_file_path = original_model.history_file_path
|
142 |
if dont_change_lora_selector:
|
143 |
return model, msg, chatbot, gr.update(), access_key, presudo_key
|
144 |
else:
|
modules/models/spark.py
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import _thread as thread
|
2 |
+
import base64
|
3 |
+
import datetime
|
4 |
+
import hashlib
|
5 |
+
import hmac
|
6 |
+
import json
|
7 |
+
from collections import deque
|
8 |
+
from urllib.parse import urlparse
|
9 |
+
import ssl
|
10 |
+
from datetime import datetime
|
11 |
+
from time import mktime
|
12 |
+
from urllib.parse import urlencode
|
13 |
+
from wsgiref.handlers import format_date_time
|
14 |
+
from threading import Condition
|
15 |
+
import websocket
|
16 |
+
import logging
|
17 |
+
|
18 |
+
from .base_model import BaseLLMModel, CallbackToIterator
|
19 |
+
|
20 |
+
|
21 |
+
class Ws_Param(object):
|
22 |
+
# 来自官方 Demo
|
23 |
+
# 初始化
|
24 |
+
def __init__(self, APPID, APIKey, APISecret, Spark_url):
|
25 |
+
self.APPID = APPID
|
26 |
+
self.APIKey = APIKey
|
27 |
+
self.APISecret = APISecret
|
28 |
+
self.host = urlparse(Spark_url).netloc
|
29 |
+
self.path = urlparse(Spark_url).path
|
30 |
+
self.Spark_url = Spark_url
|
31 |
+
|
32 |
+
# 生成url
|
33 |
+
def create_url(self):
|
34 |
+
# 生成RFC1123格式的时间戳
|
35 |
+
now = datetime.now()
|
36 |
+
date = format_date_time(mktime(now.timetuple()))
|
37 |
+
|
38 |
+
# 拼接字符串
|
39 |
+
signature_origin = "host: " + self.host + "\n"
|
40 |
+
signature_origin += "date: " + date + "\n"
|
41 |
+
signature_origin += "GET " + self.path + " HTTP/1.1"
|
42 |
+
|
43 |
+
# 进行hmac-sha256进行加密
|
44 |
+
signature_sha = hmac.new(
|
45 |
+
self.APISecret.encode("utf-8"),
|
46 |
+
signature_origin.encode("utf-8"),
|
47 |
+
digestmod=hashlib.sha256,
|
48 |
+
).digest()
|
49 |
+
|
50 |
+
signature_sha_base64 = base64.b64encode(
|
51 |
+
signature_sha).decode(encoding="utf-8")
|
52 |
+
|
53 |
+
authorization_origin = f'api_key="{self.APIKey}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature_sha_base64}"'
|
54 |
+
|
55 |
+
authorization = base64.b64encode(authorization_origin.encode("utf-8")).decode(
|
56 |
+
encoding="utf-8"
|
57 |
+
)
|
58 |
+
|
59 |
+
# 将请求的鉴权参数组合为字典
|
60 |
+
v = {"authorization": authorization, "date": date, "host": self.host}
|
61 |
+
# 拼接鉴权参数,生成url
|
62 |
+
url = self.Spark_url + "?" + urlencode(v)
|
63 |
+
# 此处打印出建立连接时候的url,参考本demo的时候可取消上方打印的注释,比对相同参数时生成的url与自己代码生成的url是否一致
|
64 |
+
return url
|
65 |
+
|
66 |
+
|
67 |
+
class Spark_Client(BaseLLMModel):
|
68 |
+
def __init__(self, model_name, appid, api_key, api_secret, user_name="") -> None:
|
69 |
+
super().__init__(model_name=model_name, user=user_name)
|
70 |
+
self.api_key = api_key
|
71 |
+
self.appid = appid
|
72 |
+
self.api_secret = api_secret
|
73 |
+
if None in [self.api_key, self.appid, self.api_secret]:
|
74 |
+
raise Exception("请在配置文件或者环境变量中设置讯飞的API Key、APP ID和API Secret")
|
75 |
+
if "2.0" in self.model_name:
|
76 |
+
self.spark_url = "wss://spark-api.xf-yun.com/v2.1/chat"
|
77 |
+
self.domain = "generalv2"
|
78 |
+
if "3.0" in self.model_name:
|
79 |
+
self.spark_url = "wss://spark-api.xf-yun.com/v3.1/chat"
|
80 |
+
self.domain = "generalv3"
|
81 |
+
else:
|
82 |
+
self.spark_url = "wss://spark-api.xf-yun.com/v1.1/chat"
|
83 |
+
self.domain = "general"
|
84 |
+
|
85 |
+
# 收到websocket错误的处理
|
86 |
+
def on_error(self, ws, error):
|
87 |
+
ws.iterator.callback("出现了错误:" + error)
|
88 |
+
|
89 |
+
# 收到websocket关闭的处理
|
90 |
+
def on_close(self, ws, one, two):
|
91 |
+
pass
|
92 |
+
|
93 |
+
# 收到websocket连接建立的处理
|
94 |
+
def on_open(self, ws):
|
95 |
+
thread.start_new_thread(self.run, (ws,))
|
96 |
+
|
97 |
+
def run(self, ws, *args):
|
98 |
+
data = json.dumps(
|
99 |
+
self.gen_params()
|
100 |
+
)
|
101 |
+
ws.send(data)
|
102 |
+
|
103 |
+
# 收到websocket消息的处理
|
104 |
+
def on_message(self, ws, message):
|
105 |
+
ws.iterator.callback(message)
|
106 |
+
|
107 |
+
def gen_params(self):
|
108 |
+
"""
|
109 |
+
通过appid和用户的提问来生成请参数
|
110 |
+
"""
|
111 |
+
data = {
|
112 |
+
"header": {"app_id": self.appid, "uid": "1234"},
|
113 |
+
"parameter": {
|
114 |
+
"chat": {
|
115 |
+
"domain": self.domain,
|
116 |
+
"random_threshold": self.temperature,
|
117 |
+
"max_tokens": 4096,
|
118 |
+
"auditing": "default",
|
119 |
+
}
|
120 |
+
},
|
121 |
+
"payload": {"message": {"text": self.history}},
|
122 |
+
}
|
123 |
+
return data
|
124 |
+
|
125 |
+
def get_answer_stream_iter(self):
|
126 |
+
wsParam = Ws_Param(self.appid, self.api_key, self.api_secret, self.spark_url)
|
127 |
+
websocket.enableTrace(False)
|
128 |
+
wsUrl = wsParam.create_url()
|
129 |
+
ws = websocket.WebSocketApp(
|
130 |
+
wsUrl,
|
131 |
+
on_message=self.on_message,
|
132 |
+
on_error=self.on_error,
|
133 |
+
on_close=self.on_close,
|
134 |
+
on_open=self.on_open,
|
135 |
+
)
|
136 |
+
ws.appid = self.appid
|
137 |
+
ws.domain = self.domain
|
138 |
+
|
139 |
+
# Initialize the CallbackToIterator
|
140 |
+
ws.iterator = CallbackToIterator()
|
141 |
+
|
142 |
+
# Start the WebSocket connection in a separate thread
|
143 |
+
thread.start_new_thread(
|
144 |
+
ws.run_forever, (), {"sslopt": {"cert_reqs": ssl.CERT_NONE}}
|
145 |
+
)
|
146 |
+
|
147 |
+
# Iterate over the CallbackToIterator instance
|
148 |
+
answer = ""
|
149 |
+
total_tokens = 0
|
150 |
+
for message in ws.iterator:
|
151 |
+
data = json.loads(message)
|
152 |
+
code = data["header"]["code"]
|
153 |
+
if code != 0:
|
154 |
+
ws.close()
|
155 |
+
raise Exception(f"请求错误: {code}, {data}")
|
156 |
+
else:
|
157 |
+
choices = data["payload"]["choices"]
|
158 |
+
status = choices["status"]
|
159 |
+
content = choices["text"][0]["content"]
|
160 |
+
if "usage" in data["payload"]:
|
161 |
+
total_tokens = data["payload"]["usage"]["text"]["total_tokens"]
|
162 |
+
answer += content
|
163 |
+
if status == 2:
|
164 |
+
ws.iterator.finish() # Finish the iterator when the status is 2
|
165 |
+
ws.close()
|
166 |
+
yield answer, total_tokens
|
modules/overwrites.py
CHANGED
@@ -44,32 +44,36 @@ def postprocess_chat_messages(
|
|
44 |
) -> str | dict | None:
|
45 |
if chat_message is None:
|
46 |
return None
|
47 |
-
elif isinstance(chat_message, (tuple, list)):
|
48 |
-
file_uri = chat_message[0]
|
49 |
-
if utils.validate_url(file_uri):
|
50 |
-
filepath = file_uri
|
51 |
-
else:
|
52 |
-
filepath = self.make_temp_copy_if_needed(file_uri)
|
53 |
-
|
54 |
-
mime_type = client_utils.get_mimetype(filepath)
|
55 |
-
return {
|
56 |
-
"name": filepath,
|
57 |
-
"mime_type": mime_type,
|
58 |
-
"alt_text": chat_message[1] if len(chat_message) > 1 else None,
|
59 |
-
"data": None, # These last two fields are filled in by the frontend
|
60 |
-
"is_file": True,
|
61 |
-
}
|
62 |
-
elif isinstance(chat_message, str):
|
63 |
-
# chat_message = inspect.cleandoc(chat_message)
|
64 |
-
# escape html spaces
|
65 |
-
# chat_message = chat_message.replace(" ", " ")
|
66 |
-
if role == "bot":
|
67 |
-
chat_message = convert_bot_before_marked(chat_message)
|
68 |
-
elif role == "user":
|
69 |
-
chat_message = convert_user_before_marked(chat_message)
|
70 |
-
return chat_message
|
71 |
else:
|
72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
|
74 |
|
75 |
|
@@ -103,4 +107,3 @@ def BlockContext_init(self, *args, **kwargs):
|
|
103 |
|
104 |
original_BlockContext_init = gr.blocks.BlockContext.__init__
|
105 |
gr.blocks.BlockContext.__init__ = BlockContext_init
|
106 |
-
|
|
|
44 |
) -> str | dict | None:
|
45 |
if chat_message is None:
|
46 |
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
else:
|
48 |
+
if isinstance(chat_message, (tuple, list)):
|
49 |
+
if len(chat_message) > 0 and "text" in chat_message[0]:
|
50 |
+
chat_message = chat_message[0]["text"]
|
51 |
+
else:
|
52 |
+
file_uri = chat_message[0]
|
53 |
+
if utils.validate_url(file_uri):
|
54 |
+
filepath = file_uri
|
55 |
+
else:
|
56 |
+
filepath = self.make_temp_copy_if_needed(file_uri)
|
57 |
+
|
58 |
+
mime_type = client_utils.get_mimetype(filepath)
|
59 |
+
return {
|
60 |
+
"name": filepath,
|
61 |
+
"mime_type": mime_type,
|
62 |
+
"alt_text": chat_message[1] if len(chat_message) > 1 else None,
|
63 |
+
"data": None, # These last two fields are filled in by the frontend
|
64 |
+
"is_file": True,
|
65 |
+
}
|
66 |
+
if isinstance(chat_message, str):
|
67 |
+
# chat_message = inspect.cleandoc(chat_message)
|
68 |
+
# escape html spaces
|
69 |
+
# chat_message = chat_message.replace(" ", " ")
|
70 |
+
if role == "bot":
|
71 |
+
chat_message = convert_bot_before_marked(chat_message)
|
72 |
+
elif role == "user":
|
73 |
+
chat_message = convert_user_before_marked(chat_message)
|
74 |
+
return chat_message
|
75 |
+
else:
|
76 |
+
raise ValueError(f"Invalid message for Chatbot component: {chat_message}")
|
77 |
|
78 |
|
79 |
|
|
|
107 |
|
108 |
original_BlockContext_init = gr.blocks.BlockContext.__init__
|
109 |
gr.blocks.BlockContext.__init__ = BlockContext_init
|
|
modules/presets.py
CHANGED
@@ -14,7 +14,9 @@ LLAMA_INFERENCER = None
|
|
14 |
# ChatGPT 设置
|
15 |
INITIAL_SYSTEM_PROMPT = "You are a helpful assistant."
|
16 |
API_HOST = "api.openai.com"
|
17 |
-
|
|
|
|
|
18 |
BALANCE_API_URL="https://api.openai.com/dashboard/billing/credit_grants"
|
19 |
USAGE_API_URL="https://api.openai.com/dashboard/billing/usage"
|
20 |
HISTORY_DIR = Path("history")
|
@@ -36,6 +38,7 @@ BILLING_NOT_APPLICABLE_MSG = i18n("账单信息不适用") # 本地运行的模
|
|
36 |
TIMEOUT_STREAMING = 60 # 流式对话时的超时时间
|
37 |
TIMEOUT_ALL = 200 # 非流式对话时的超时时间
|
38 |
ENABLE_STREAMING_OPTION = True # 是否启用选择选择是否实时显示回答的勾选框
|
|
|
39 |
HIDE_MY_KEY = False # 如果你想在UI中隐藏你的 API 密钥,将此值设置为 True
|
40 |
CONCURRENT_COUNT = 100 # 允许同时使用的用户数量
|
41 |
|
@@ -48,16 +51,15 @@ CHUANHU_DESCRIPTION = i18n("由Bilibili [土川虎虎虎](https://space.bilibili
|
|
48 |
|
49 |
|
50 |
ONLINE_MODELS = [
|
51 |
-
"
|
52 |
-
"
|
53 |
-
"
|
54 |
-
"
|
55 |
-
"
|
56 |
-
"
|
57 |
-
"
|
58 |
-
"
|
59 |
-
"
|
60 |
-
"gpt-4-32k-0613",
|
61 |
"川虎助理",
|
62 |
"川虎助理 Pro",
|
63 |
"GooglePaLM",
|
@@ -67,9 +69,12 @@ ONLINE_MODELS = [
|
|
67 |
"yuanai-1.0-translate",
|
68 |
"yuanai-1.0-dialog",
|
69 |
"yuanai-1.0-rhythm_poems",
|
70 |
-
"minimax-abab4-chat",
|
71 |
"minimax-abab5-chat",
|
72 |
-
"midjourney"
|
|
|
|
|
|
|
|
|
73 |
]
|
74 |
|
75 |
LOCAL_MODELS = [
|
@@ -80,12 +85,69 @@ LOCAL_MODELS = [
|
|
80 |
"chatglm2-6b-int4",
|
81 |
"StableLM",
|
82 |
"MOSS",
|
83 |
-
"
|
84 |
-
"
|
85 |
-
"
|
86 |
-
"llama-65b-hf",
|
87 |
]
|
88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
if os.environ.get('HIDE_LOCAL_MODELS', 'false') == 'true':
|
90 |
MODELS = ONLINE_MODELS
|
91 |
else:
|
@@ -101,19 +163,6 @@ for dir_name in os.listdir("models"):
|
|
101 |
if dir_name not in MODELS:
|
102 |
MODELS.append(dir_name)
|
103 |
|
104 |
-
MODEL_TOKEN_LIMIT = {
|
105 |
-
"gpt-3.5-turbo": 4096,
|
106 |
-
"gpt-3.5-turbo-16k": 16384,
|
107 |
-
"gpt-3.5-turbo-0301": 4096,
|
108 |
-
"gpt-3.5-turbo-0613": 4096,
|
109 |
-
"gpt-4": 8192,
|
110 |
-
"gpt-4-0314": 8192,
|
111 |
-
"gpt-4-0613": 8192,
|
112 |
-
"gpt-4-32k": 32768,
|
113 |
-
"gpt-4-32k-0314": 32768,
|
114 |
-
"gpt-4-32k-0613": 32768
|
115 |
-
}
|
116 |
-
|
117 |
TOKEN_OFFSET = 1000 # 模型的token上限减去这个值,得到软上限。到达软上限之后,自动尝试减少token占用。
|
118 |
DEFAULT_TOKEN_LIMIT = 3000 # 默认的token上限
|
119 |
REDUCE_TOKEN_FACTOR = 0.5 # 与模型token上限想乘,得到目标token数。减少token占用时,将token占用减少到目标token数以下。
|
@@ -125,11 +174,18 @@ REPLY_LANGUAGES = [
|
|
125 |
"日本語",
|
126 |
"Español",
|
127 |
"Français",
|
|
|
128 |
"Deutsch",
|
129 |
"한국어",
|
130 |
"跟随问题语言(不稳定)"
|
131 |
]
|
132 |
|
|
|
|
|
|
|
|
|
|
|
|
|
133 |
|
134 |
WEBSEARCH_PTOMPT_TEMPLATE = """\
|
135 |
Web search results:
|
@@ -175,6 +231,15 @@ SUMMARIZE_PROMPT = """Write a concise summary of the following:
|
|
175 |
|
176 |
CONCISE SUMMARY IN 中文:"""
|
177 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
178 |
ALREADY_CONVERTED_MARK = "<!-- ALREADY CONVERTED BY PARSER. -->"
|
179 |
START_OF_OUTPUT_MARK = "<!-- SOO IN MESSAGE -->"
|
180 |
END_OF_OUTPUT_MARK = "<!-- EOO IN MESSAGE -->"
|
@@ -243,6 +308,7 @@ small_and_beautiful_theme = gr.themes.Soft(
|
|
243 |
block_title_background_fill_dark="*primary_900",
|
244 |
block_label_background_fill_dark="*primary_900",
|
245 |
input_background_fill="#F6F6F6",
|
246 |
-
chatbot_code_background_color="*neutral_950",
|
|
|
247 |
chatbot_code_background_color_dark="*neutral_950",
|
248 |
)
|
|
|
14 |
# ChatGPT 设置
|
15 |
INITIAL_SYSTEM_PROMPT = "You are a helpful assistant."
|
16 |
API_HOST = "api.openai.com"
|
17 |
+
OPENAI_API_BASE = "https://api.openai.com/v1"
|
18 |
+
CHAT_COMPLETION_URL = "https://api.openai.com/v1/chat/completions"
|
19 |
+
COMPLETION_URL = "https://api.openai.com/v1/completions"
|
20 |
BALANCE_API_URL="https://api.openai.com/dashboard/billing/credit_grants"
|
21 |
USAGE_API_URL="https://api.openai.com/dashboard/billing/usage"
|
22 |
HISTORY_DIR = Path("history")
|
|
|
38 |
TIMEOUT_STREAMING = 60 # 流式对话时的超时时间
|
39 |
TIMEOUT_ALL = 200 # 非流式对话时的超时时间
|
40 |
ENABLE_STREAMING_OPTION = True # 是否启用选择选择是否实时显示回答的勾选框
|
41 |
+
ENABLE_LLM_NAME_CHAT_OPTION = True # 是否启用选择是否使用LLM模型的勾选框
|
42 |
HIDE_MY_KEY = False # 如果你想在UI中隐藏你的 API 密钥,将此值设置为 True
|
43 |
CONCURRENT_COUNT = 100 # 允许同时使用的用户数量
|
44 |
|
|
|
51 |
|
52 |
|
53 |
ONLINE_MODELS = [
|
54 |
+
"GPT3.5 Turbo",
|
55 |
+
"GPT3.5 Turbo Instruct",
|
56 |
+
"GPT3.5 Turbo 16K",
|
57 |
+
"GPT3.5 Turbo 0301",
|
58 |
+
"GPT3.5 Turbo 0613",
|
59 |
+
"GPT4",
|
60 |
+
"GPT4 32K",
|
61 |
+
"GPT4 Turbo",
|
62 |
+
"GPT4 Vision",
|
|
|
63 |
"川虎助理",
|
64 |
"川虎助理 Pro",
|
65 |
"GooglePaLM",
|
|
|
69 |
"yuanai-1.0-translate",
|
70 |
"yuanai-1.0-dialog",
|
71 |
"yuanai-1.0-rhythm_poems",
|
|
|
72 |
"minimax-abab5-chat",
|
73 |
+
"midjourney",
|
74 |
+
"讯飞星火大模型V3.0",
|
75 |
+
"讯飞星火大模型V2.0",
|
76 |
+
"讯飞星火大模型V1.5",
|
77 |
+
"Claude"
|
78 |
]
|
79 |
|
80 |
LOCAL_MODELS = [
|
|
|
85 |
"chatglm2-6b-int4",
|
86 |
"StableLM",
|
87 |
"MOSS",
|
88 |
+
"Llama-2-7B-Chat",
|
89 |
+
"Qwen 7B",
|
90 |
+
"Qwen 14B"
|
|
|
91 |
]
|
92 |
|
93 |
+
# Additional metadata for online and local models
|
94 |
+
MODEL_METADATA = {
|
95 |
+
"Llama-2-7B":{
|
96 |
+
"repo_id": "TheBloke/Llama-2-7B-GGUF",
|
97 |
+
"filelist": ["llama-2-7b.Q6_K.gguf"],
|
98 |
+
},
|
99 |
+
"Llama-2-7B-Chat":{
|
100 |
+
"repo_id": "TheBloke/Llama-2-7b-Chat-GGUF",
|
101 |
+
"filelist": ["llama-2-7b-chat.Q6_K.gguf"],
|
102 |
+
},
|
103 |
+
"Qwen 7B": {
|
104 |
+
"repo_id": "Qwen/Qwen-7B-Chat-Int4",
|
105 |
+
},
|
106 |
+
"Qwen 14B": {
|
107 |
+
"repo_id": "Qwen/Qwen-14B-Chat-Int4",
|
108 |
+
},
|
109 |
+
"GPT3.5 Turbo": {
|
110 |
+
"model_name": "gpt-3.5-turbo",
|
111 |
+
"token_limit": 4096,
|
112 |
+
},
|
113 |
+
"GPT3.5 Turbo Instruct": {
|
114 |
+
"model_name": "gpt-3.5-turbo-instruct",
|
115 |
+
"token_limit": 4096,
|
116 |
+
},
|
117 |
+
"GPT3.5 Turbo 16K": {
|
118 |
+
"model_name": "gpt-3.5-turbo-16k",
|
119 |
+
"token_limit": 16384,
|
120 |
+
},
|
121 |
+
"GPT3.5 Turbo 0301": {
|
122 |
+
"model_name": "gpt-3.5-turbo-0301",
|
123 |
+
"token_limit": 4096,
|
124 |
+
},
|
125 |
+
"GPT3.5 Turbo 0613": {
|
126 |
+
"model_name": "gpt-3.5-turbo-0613",
|
127 |
+
"token_limit": 4096,
|
128 |
+
},
|
129 |
+
"GPT4": {
|
130 |
+
"model_name": "gpt-4",
|
131 |
+
"token_limit": 8192,
|
132 |
+
},
|
133 |
+
"GPT4 32K": {
|
134 |
+
"model_name": "gpt-4-32k",
|
135 |
+
"token_limit": 32768,
|
136 |
+
},
|
137 |
+
"GPT4 Turbo": {
|
138 |
+
"model_name": "gpt-4-1106-preview",
|
139 |
+
"token_limit": 128000,
|
140 |
+
},
|
141 |
+
"GPT4 Vision": {
|
142 |
+
"model_name": "gpt-4-vision-preview",
|
143 |
+
"token_limit": 128000,
|
144 |
+
},
|
145 |
+
"Claude": {
|
146 |
+
"model_name": "Claude",
|
147 |
+
"token_limit": 4096,
|
148 |
+
},
|
149 |
+
}
|
150 |
+
|
151 |
if os.environ.get('HIDE_LOCAL_MODELS', 'false') == 'true':
|
152 |
MODELS = ONLINE_MODELS
|
153 |
else:
|
|
|
163 |
if dir_name not in MODELS:
|
164 |
MODELS.append(dir_name)
|
165 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
166 |
TOKEN_OFFSET = 1000 # 模型的token上限减去这个值,得到软上限。到达软上限之后,自动尝试减少token占用。
|
167 |
DEFAULT_TOKEN_LIMIT = 3000 # 默认的token上限
|
168 |
REDUCE_TOKEN_FACTOR = 0.5 # 与模型token上限想乘,得到目标token数。减少token占用时,将token占用减少到目标token数以下。
|
|
|
174 |
"日本語",
|
175 |
"Español",
|
176 |
"Français",
|
177 |
+
"Russian",
|
178 |
"Deutsch",
|
179 |
"한국어",
|
180 |
"跟随问题语言(不稳定)"
|
181 |
]
|
182 |
|
183 |
+
HISTORY_NAME_METHODS = [
|
184 |
+
i18n("根据日期时间"),
|
185 |
+
i18n("第一条提问"),
|
186 |
+
i18n("模型自动总结(消耗tokens)"),
|
187 |
+
]
|
188 |
+
|
189 |
|
190 |
WEBSEARCH_PTOMPT_TEMPLATE = """\
|
191 |
Web search results:
|
|
|
231 |
|
232 |
CONCISE SUMMARY IN 中文:"""
|
233 |
|
234 |
+
SUMMARY_CHAT_SYSTEM_PROMPT = """\
|
235 |
+
Please summarize the following conversation for a chat topic.
|
236 |
+
No more than 16 characters.
|
237 |
+
No special characters.
|
238 |
+
Punctuation mark is banned.
|
239 |
+
Not including '.' ':' '?' '!' '“' '*' '<' '>'.
|
240 |
+
Reply in user's language.
|
241 |
+
"""
|
242 |
+
|
243 |
ALREADY_CONVERTED_MARK = "<!-- ALREADY CONVERTED BY PARSER. -->"
|
244 |
START_OF_OUTPUT_MARK = "<!-- SOO IN MESSAGE -->"
|
245 |
END_OF_OUTPUT_MARK = "<!-- EOO IN MESSAGE -->"
|
|
|
308 |
block_title_background_fill_dark="*primary_900",
|
309 |
block_label_background_fill_dark="*primary_900",
|
310 |
input_background_fill="#F6F6F6",
|
311 |
+
# chatbot_code_background_color="*neutral_950",
|
312 |
+
# gradio 会把这个几个chatbot打头的变量应用到其他md渲染的地方,鬼晓得怎么想的。。。
|
313 |
chatbot_code_background_color_dark="*neutral_950",
|
314 |
)
|
modules/repo.py
CHANGED
@@ -6,30 +6,33 @@ from functools import lru_cache
|
|
6 |
import logging
|
7 |
import gradio as gr
|
8 |
import datetime
|
|
|
9 |
|
10 |
# This file is mainly used to describe repo version info, execute the git command, python pip command, shell command, etc.
|
11 |
# Part of the code in this file is referenced from stable-diffusion-webui/modules/launch_utils.py
|
12 |
|
13 |
python = sys.executable
|
14 |
-
pip = os.environ.get(
|
15 |
-
git = os.environ.get(
|
16 |
|
17 |
# Pypi index url
|
18 |
-
index_url = os.environ.get(
|
19 |
|
20 |
# Whether to default to printing command output
|
21 |
default_command_live = True
|
22 |
|
23 |
|
24 |
-
def run(
|
|
|
|
|
25 |
if desc is not None:
|
26 |
print(desc)
|
27 |
run_kwargs = {
|
28 |
"args": command,
|
29 |
"shell": True,
|
30 |
"env": os.environ if custom_env is None else custom_env,
|
31 |
-
"encoding":
|
32 |
-
"errors":
|
33 |
}
|
34 |
|
35 |
if not live:
|
@@ -48,29 +51,32 @@ def run(command, desc=None, errdesc=None, custom_env=None, live: bool = default_
|
|
48 |
error_bits.append(f"stderr: {result.stderr}")
|
49 |
raise RuntimeError("\n".join(error_bits))
|
50 |
|
51 |
-
return
|
52 |
|
53 |
|
54 |
def run_pip(command, desc=None, pref=None, live=default_command_live):
|
55 |
# if args.skip_install:
|
56 |
# return
|
57 |
|
58 |
-
index_url_line = f
|
59 |
return run(
|
60 |
-
f'"{python}" -m pip {command} --prefer-binary{index_url_line}',
|
61 |
-
desc=f"{pref} Installing {desc}...",
|
62 |
-
errdesc=f"Couldn't install {desc}",
|
63 |
-
live=live
|
64 |
)
|
65 |
|
66 |
|
67 |
@lru_cache()
|
68 |
def commit_hash():
|
69 |
try:
|
70 |
-
return subprocess.check_output(
|
|
|
|
|
71 |
except Exception:
|
72 |
return "<none>"
|
73 |
|
|
|
74 |
def commit_html():
|
75 |
commit = commit_hash()
|
76 |
if commit != "<none>":
|
@@ -80,6 +86,7 @@ def commit_html():
|
|
80 |
commit_info = "unknown \U0001F615"
|
81 |
return commit_info
|
82 |
|
|
|
83 |
@lru_cache()
|
84 |
def tag_html():
|
85 |
try:
|
@@ -87,7 +94,7 @@ def tag_html():
|
|
87 |
try:
|
88 |
# tag = subprocess.check_output([git, "describe", "--tags", "--exact-match"], shell=False, encoding='utf8').strip()
|
89 |
tag = run(f"{git} describe --tags --exact-match", live=False).strip()
|
90 |
-
except Exception:
|
91 |
tag = "<edited>"
|
92 |
except Exception:
|
93 |
tag = "<none>"
|
@@ -98,14 +105,16 @@ def tag_html():
|
|
98 |
tag_info = f'<a style="text-decoration:none;color:inherit" href="https://github.com/GaiZhenbiao/ChuanhuChatGPT/releases/tag/{latest_tag}">{latest_tag}</a><span style="font-size:smaller">*</span>'
|
99 |
else:
|
100 |
tag_info = f'<a style="text-decoration:none;color:inherit" href="https://github.com/GaiZhenbiao/ChuanhuChatGPT/releases/tag/{tag}">{tag}</a>'
|
101 |
-
|
102 |
return tag_info
|
103 |
|
|
|
104 |
def repo_tag_html():
|
105 |
commit_version = commit_html()
|
106 |
tag_version = tag_html()
|
107 |
return tag_version if tag_version != "unknown \U0001F615" else commit_version
|
108 |
|
|
|
109 |
def versions_html():
|
110 |
python_version = ".".join([str(x) for x in sys.version_info[0:3]])
|
111 |
repo_version = repo_tag_html()
|
@@ -117,20 +126,44 @@ def versions_html():
|
|
117 |
<a style="text-decoration:none;color:inherit" href="https://github.com/GaiZhenbiao/ChuanhuChatGPT">ChuanhuChat</a>: {repo_version}
|
118 |
"""
|
119 |
|
|
|
120 |
def version_time():
|
|
|
|
|
|
|
121 |
try:
|
122 |
-
|
123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
except Exception:
|
125 |
commit_time = "unknown"
|
126 |
return commit_time
|
127 |
|
128 |
|
129 |
-
|
130 |
def get_current_branch():
|
131 |
try:
|
132 |
# branch = run(f"{git} rev-parse --abbrev-ref HEAD").strip()
|
133 |
-
branch = subprocess.check_output(
|
|
|
|
|
134 |
except Exception:
|
135 |
branch = "<none>"
|
136 |
return branch
|
@@ -139,7 +172,10 @@ def get_current_branch():
|
|
139 |
def get_latest_release():
|
140 |
try:
|
141 |
import requests
|
142 |
-
|
|
|
|
|
|
|
143 |
tag = release["tag_name"]
|
144 |
release_note = release["body"]
|
145 |
need_pip = release_note.find("requirements reinstall needed") != -1
|
@@ -149,21 +185,34 @@ def get_latest_release():
|
|
149 |
need_pip = False
|
150 |
return {"tag": tag, "release_note": release_note, "need_pip": need_pip}
|
151 |
|
|
|
152 |
def get_tag_commit_hash(tag):
|
153 |
try:
|
154 |
import requests
|
155 |
-
|
|
|
|
|
|
|
156 |
commit_hash = [x["commit"]["sha"] for x in tags if x["name"] == tag][0]
|
157 |
except Exception:
|
158 |
commit_hash = "<none>"
|
159 |
return commit_hash
|
160 |
|
|
|
161 |
def repo_need_stash():
|
162 |
try:
|
163 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
except Exception:
|
165 |
return True
|
166 |
|
|
|
167 |
def background_update():
|
168 |
# {git} fetch --all && ({git} pull https://github.com/GaiZhenbiao/ChuanhuChatGPT.git main -f || ({git} stash && {git} pull https://github.com/GaiZhenbiao/ChuanhuChatGPT.git main -f && {git} stash pop)) && {pip} install -r requirements.txt")
|
169 |
try:
|
@@ -175,50 +224,83 @@ def background_update():
|
|
175 |
|
176 |
timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
|
177 |
current_branch = get_current_branch()
|
178 |
-
updater_branch = f
|
179 |
-
backup_branch = f
|
180 |
track_repo = "https://github.com/GaiZhenbiao/ChuanhuChatGPT.git"
|
181 |
try:
|
182 |
try:
|
183 |
-
run(
|
|
|
|
|
|
|
|
|
184 |
except Exception:
|
185 |
-
logging.error(
|
|
|
|
|
186 |
return "failed"
|
187 |
-
|
188 |
-
run(
|
189 |
-
|
190 |
-
|
|
|
|
|
|
|
191 |
run(f"{git} checkout -b {backup_branch}", live=False)
|
192 |
run(f"{git} checkout -b {updater_branch}", live=False)
|
193 |
run(f"{git} reset --hard FETCH_HEAD", live=False)
|
194 |
-
run(
|
|
|
|
|
|
|
|
|
195 |
run(f"{git} checkout {current_branch}", live=False)
|
196 |
-
|
197 |
try:
|
198 |
-
run(
|
|
|
|
|
|
|
199 |
except Exception:
|
200 |
logging.error(f"Update failed in merging")
|
201 |
try:
|
202 |
-
run(
|
|
|
|
|
|
|
203 |
run(f"{git} reset --hard {backup_branch}", live=False)
|
204 |
run(f"{git} branch -D -f {updater_branch}", live=False)
|
205 |
run(f"{git} branch -D -f {backup_branch}", live=False)
|
206 |
run(f"{git} stash pop", live=False) if need_stash else None
|
207 |
-
logging.error(
|
|
|
|
|
208 |
return "failed"
|
209 |
except Exception as e:
|
210 |
-
logging.error(
|
|
|
|
|
211 |
return "failed"
|
212 |
|
213 |
if need_stash:
|
214 |
try:
|
215 |
-
run(
|
|
|
|
|
|
|
|
|
216 |
except Exception:
|
217 |
-
run(
|
|
|
|
|
|
|
|
|
218 |
run(f"{git} branch -D -f {updater_branch}", live=False)
|
219 |
run(f"{git} branch -D -f {backup_branch}", live=False)
|
220 |
run(f"{git} stash pop", live=False)
|
221 |
-
logging.error(
|
|
|
|
|
222 |
return "failed"
|
223 |
run(f"{git} stash drop", live=False)
|
224 |
|
@@ -228,12 +310,17 @@ def background_update():
|
|
228 |
logging.error(f"Update failed: {e}")
|
229 |
return "failed"
|
230 |
if need_pip:
|
231 |
-
try:
|
232 |
-
run_pip(
|
|
|
|
|
|
|
|
|
|
|
233 |
except Exception:
|
234 |
logging.error(f"Update failed in pip install")
|
235 |
return "failed"
|
236 |
return "success"
|
237 |
except Exception as e:
|
238 |
logging.error(f"Update failed: {e}")
|
239 |
-
return "failed"
|
|
|
6 |
import logging
|
7 |
import gradio as gr
|
8 |
import datetime
|
9 |
+
import platform
|
10 |
|
11 |
# This file is mainly used to describe repo version info, execute the git command, python pip command, shell command, etc.
|
12 |
# Part of the code in this file is referenced from stable-diffusion-webui/modules/launch_utils.py
|
13 |
|
14 |
python = sys.executable
|
15 |
+
pip = os.environ.get("PIP", "pip")
|
16 |
+
git = os.environ.get("GIT", "git")
|
17 |
|
18 |
# Pypi index url
|
19 |
+
index_url = os.environ.get("INDEX_URL", "")
|
20 |
|
21 |
# Whether to default to printing command output
|
22 |
default_command_live = True
|
23 |
|
24 |
|
25 |
+
def run(
|
26 |
+
command, desc=None, errdesc=None, custom_env=None, live: bool = default_command_live
|
27 |
+
) -> str:
|
28 |
if desc is not None:
|
29 |
print(desc)
|
30 |
run_kwargs = {
|
31 |
"args": command,
|
32 |
"shell": True,
|
33 |
"env": os.environ if custom_env is None else custom_env,
|
34 |
+
"encoding": "utf8",
|
35 |
+
"errors": "ignore",
|
36 |
}
|
37 |
|
38 |
if not live:
|
|
|
51 |
error_bits.append(f"stderr: {result.stderr}")
|
52 |
raise RuntimeError("\n".join(error_bits))
|
53 |
|
54 |
+
return result.stdout or ""
|
55 |
|
56 |
|
57 |
def run_pip(command, desc=None, pref=None, live=default_command_live):
|
58 |
# if args.skip_install:
|
59 |
# return
|
60 |
|
61 |
+
index_url_line = f" --index-url {index_url}" if index_url != "" else ""
|
62 |
return run(
|
63 |
+
f'"{python}" -m pip {command} --prefer-binary{index_url_line}',
|
64 |
+
desc=f"{pref} Installing {desc}...",
|
65 |
+
errdesc=f"Couldn't install {desc}",
|
66 |
+
live=live,
|
67 |
)
|
68 |
|
69 |
|
70 |
@lru_cache()
|
71 |
def commit_hash():
|
72 |
try:
|
73 |
+
return subprocess.check_output(
|
74 |
+
[git, "rev-parse", "HEAD"], shell=False, encoding="utf8"
|
75 |
+
).strip()
|
76 |
except Exception:
|
77 |
return "<none>"
|
78 |
|
79 |
+
|
80 |
def commit_html():
|
81 |
commit = commit_hash()
|
82 |
if commit != "<none>":
|
|
|
86 |
commit_info = "unknown \U0001F615"
|
87 |
return commit_info
|
88 |
|
89 |
+
|
90 |
@lru_cache()
|
91 |
def tag_html():
|
92 |
try:
|
|
|
94 |
try:
|
95 |
# tag = subprocess.check_output([git, "describe", "--tags", "--exact-match"], shell=False, encoding='utf8').strip()
|
96 |
tag = run(f"{git} describe --tags --exact-match", live=False).strip()
|
97 |
+
except Exception:
|
98 |
tag = "<edited>"
|
99 |
except Exception:
|
100 |
tag = "<none>"
|
|
|
105 |
tag_info = f'<a style="text-decoration:none;color:inherit" href="https://github.com/GaiZhenbiao/ChuanhuChatGPT/releases/tag/{latest_tag}">{latest_tag}</a><span style="font-size:smaller">*</span>'
|
106 |
else:
|
107 |
tag_info = f'<a style="text-decoration:none;color:inherit" href="https://github.com/GaiZhenbiao/ChuanhuChatGPT/releases/tag/{tag}">{tag}</a>'
|
108 |
+
|
109 |
return tag_info
|
110 |
|
111 |
+
|
112 |
def repo_tag_html():
|
113 |
commit_version = commit_html()
|
114 |
tag_version = tag_html()
|
115 |
return tag_version if tag_version != "unknown \U0001F615" else commit_version
|
116 |
|
117 |
+
|
118 |
def versions_html():
|
119 |
python_version = ".".join([str(x) for x in sys.version_info[0:3]])
|
120 |
repo_version = repo_tag_html()
|
|
|
126 |
<a style="text-decoration:none;color:inherit" href="https://github.com/GaiZhenbiao/ChuanhuChatGPT">ChuanhuChat</a>: {repo_version}
|
127 |
"""
|
128 |
|
129 |
+
|
130 |
def version_time():
|
131 |
+
git = "git"
|
132 |
+
cmd = f"{git} log -1 --format=%cd --date=iso-strict"
|
133 |
+
commit_time = "unknown"
|
134 |
try:
|
135 |
+
if platform.system() == "Windows":
|
136 |
+
# For Windows
|
137 |
+
env = dict(os.environ) # copy the current environment
|
138 |
+
env["TZ"] = "UTC" # set timezone to UTC
|
139 |
+
raw_commit_time = subprocess.check_output(
|
140 |
+
cmd, shell=True, encoding="utf8", env=env
|
141 |
+
).strip()
|
142 |
+
else:
|
143 |
+
# For Unix systems
|
144 |
+
cmd = f"TZ=UTC {cmd}"
|
145 |
+
raw_commit_time = subprocess.check_output(
|
146 |
+
cmd, shell=True, encoding="utf8"
|
147 |
+
).strip()
|
148 |
+
|
149 |
+
# Convert the date-time to the desired format
|
150 |
+
commit_datetime = datetime.datetime.strptime(
|
151 |
+
raw_commit_time, "%Y-%m-%dT%H:%M:%S%z"
|
152 |
+
)
|
153 |
+
commit_time = commit_datetime.strftime("%Y-%m-%dT%H:%M:%SZ")
|
154 |
+
|
155 |
+
# logging.info(f"commit time: {commit_time}")
|
156 |
except Exception:
|
157 |
commit_time = "unknown"
|
158 |
return commit_time
|
159 |
|
160 |
|
|
|
161 |
def get_current_branch():
|
162 |
try:
|
163 |
# branch = run(f"{git} rev-parse --abbrev-ref HEAD").strip()
|
164 |
+
branch = subprocess.check_output(
|
165 |
+
[git, "rev-parse", "--abbrev-ref", "HEAD"], shell=False, encoding="utf8"
|
166 |
+
).strip()
|
167 |
except Exception:
|
168 |
branch = "<none>"
|
169 |
return branch
|
|
|
172 |
def get_latest_release():
|
173 |
try:
|
174 |
import requests
|
175 |
+
|
176 |
+
release = requests.get(
|
177 |
+
"https://api.github.com/repos/GaiZhenbiao/ChuanhuChatGPT/releases/latest"
|
178 |
+
).json()
|
179 |
tag = release["tag_name"]
|
180 |
release_note = release["body"]
|
181 |
need_pip = release_note.find("requirements reinstall needed") != -1
|
|
|
185 |
need_pip = False
|
186 |
return {"tag": tag, "release_note": release_note, "need_pip": need_pip}
|
187 |
|
188 |
+
|
189 |
def get_tag_commit_hash(tag):
|
190 |
try:
|
191 |
import requests
|
192 |
+
|
193 |
+
tags = requests.get(
|
194 |
+
"https://api.github.com/repos/GaiZhenbiao/ChuanhuChatGPT/tags"
|
195 |
+
).json()
|
196 |
commit_hash = [x["commit"]["sha"] for x in tags if x["name"] == tag][0]
|
197 |
except Exception:
|
198 |
commit_hash = "<none>"
|
199 |
return commit_hash
|
200 |
|
201 |
+
|
202 |
def repo_need_stash():
|
203 |
try:
|
204 |
+
return (
|
205 |
+
subprocess.check_output(
|
206 |
+
[git, "diff-index", "--quiet", "HEAD", "--"],
|
207 |
+
shell=False,
|
208 |
+
encoding="utf8",
|
209 |
+
).strip()
|
210 |
+
!= ""
|
211 |
+
)
|
212 |
except Exception:
|
213 |
return True
|
214 |
|
215 |
+
|
216 |
def background_update():
|
217 |
# {git} fetch --all && ({git} pull https://github.com/GaiZhenbiao/ChuanhuChatGPT.git main -f || ({git} stash && {git} pull https://github.com/GaiZhenbiao/ChuanhuChatGPT.git main -f && {git} stash pop)) && {pip} install -r requirements.txt")
|
218 |
try:
|
|
|
224 |
|
225 |
timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
|
226 |
current_branch = get_current_branch()
|
227 |
+
updater_branch = f"tmp_{timestamp}"
|
228 |
+
backup_branch = f"backup_{timestamp}"
|
229 |
track_repo = "https://github.com/GaiZhenbiao/ChuanhuChatGPT.git"
|
230 |
try:
|
231 |
try:
|
232 |
+
run(
|
233 |
+
f"{git} fetch {track_repo}",
|
234 |
+
desc="[Updater] Fetching from github...",
|
235 |
+
live=False,
|
236 |
+
)
|
237 |
except Exception:
|
238 |
+
logging.error(
|
239 |
+
f"Update failed in fetching, check your network connection"
|
240 |
+
)
|
241 |
return "failed"
|
242 |
+
|
243 |
+
run(
|
244 |
+
f'{git} stash push --include-untracked -m "updater-{timestamp}"',
|
245 |
+
desc=f"[Updater] Restoring you local changes on stash updater-{timestamp}",
|
246 |
+
live=False,
|
247 |
+
) if need_stash else None
|
248 |
+
|
249 |
run(f"{git} checkout -b {backup_branch}", live=False)
|
250 |
run(f"{git} checkout -b {updater_branch}", live=False)
|
251 |
run(f"{git} reset --hard FETCH_HEAD", live=False)
|
252 |
+
run(
|
253 |
+
f"{git} reset --hard {latest_release_hash}",
|
254 |
+
desc=f"[Updater] Checking out {latest_release_tag}...",
|
255 |
+
live=False,
|
256 |
+
)
|
257 |
run(f"{git} checkout {current_branch}", live=False)
|
258 |
+
|
259 |
try:
|
260 |
+
run(
|
261 |
+
f"{git} merge --no-edit {updater_branch} -q",
|
262 |
+
desc=f"[Updater] Trying to apply latest update on version {latest_release_tag}...",
|
263 |
+
)
|
264 |
except Exception:
|
265 |
logging.error(f"Update failed in merging")
|
266 |
try:
|
267 |
+
run(
|
268 |
+
f"{git} merge --abort",
|
269 |
+
desc="[Updater] Conflict detected, canceling update...",
|
270 |
+
)
|
271 |
run(f"{git} reset --hard {backup_branch}", live=False)
|
272 |
run(f"{git} branch -D -f {updater_branch}", live=False)
|
273 |
run(f"{git} branch -D -f {backup_branch}", live=False)
|
274 |
run(f"{git} stash pop", live=False) if need_stash else None
|
275 |
+
logging.error(
|
276 |
+
f"Update failed, but your file was safely reset to the state before the update."
|
277 |
+
)
|
278 |
return "failed"
|
279 |
except Exception as e:
|
280 |
+
logging.error(
|
281 |
+
f"!!!Update failed in resetting, try to reset your files manually. {e}"
|
282 |
+
)
|
283 |
return "failed"
|
284 |
|
285 |
if need_stash:
|
286 |
try:
|
287 |
+
run(
|
288 |
+
f"{git} stash apply",
|
289 |
+
desc="[Updater] Trying to restore your local modifications...",
|
290 |
+
live=False,
|
291 |
+
)
|
292 |
except Exception:
|
293 |
+
run(
|
294 |
+
f"{git} reset --hard {backup_branch}",
|
295 |
+
desc="[Updater] Conflict detected, canceling update...",
|
296 |
+
live=False,
|
297 |
+
)
|
298 |
run(f"{git} branch -D -f {updater_branch}", live=False)
|
299 |
run(f"{git} branch -D -f {backup_branch}", live=False)
|
300 |
run(f"{git} stash pop", live=False)
|
301 |
+
logging.error(
|
302 |
+
f"Update failed in applying your local changes, but your file was safely reset to the state before the update."
|
303 |
+
)
|
304 |
return "failed"
|
305 |
run(f"{git} stash drop", live=False)
|
306 |
|
|
|
310 |
logging.error(f"Update failed: {e}")
|
311 |
return "failed"
|
312 |
if need_pip:
|
313 |
+
try:
|
314 |
+
run_pip(
|
315 |
+
f"install -r requirements.txt",
|
316 |
+
pref="[Updater]",
|
317 |
+
desc="requirements",
|
318 |
+
live=False,
|
319 |
+
)
|
320 |
except Exception:
|
321 |
logging.error(f"Update failed in pip install")
|
322 |
return "failed"
|
323 |
return "success"
|
324 |
except Exception as e:
|
325 |
logging.error(f"Update failed: {e}")
|
326 |
+
return "failed"
|
modules/shared.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
from modules.presets import
|
2 |
import os
|
3 |
import queue
|
4 |
import openai
|
@@ -6,9 +6,10 @@ import openai
|
|
6 |
class State:
|
7 |
interrupted = False
|
8 |
multi_api_key = False
|
9 |
-
|
10 |
balance_api_url = BALANCE_API_URL
|
11 |
usage_api_url = USAGE_API_URL
|
|
|
12 |
|
13 |
def interrupt(self):
|
14 |
self.interrupted = True
|
@@ -22,13 +23,14 @@ class State:
|
|
22 |
api_host = f"https://{api_host}"
|
23 |
if api_host.endswith("/v1"):
|
24 |
api_host = api_host[:-3]
|
25 |
-
self.
|
|
|
26 |
self.balance_api_url = f"{api_host}/dashboard/billing/credit_grants"
|
27 |
self.usage_api_url = f"{api_host}/dashboard/billing/usage"
|
28 |
os.environ["OPENAI_API_BASE"] = api_host
|
29 |
|
30 |
def reset_api_host(self):
|
31 |
-
self.
|
32 |
self.balance_api_url = BALANCE_API_URL
|
33 |
self.usage_api_url = USAGE_API_URL
|
34 |
os.environ["OPENAI_API_BASE"] = f"https://{API_HOST}"
|
@@ -36,7 +38,7 @@ class State:
|
|
36 |
|
37 |
def reset_all(self):
|
38 |
self.interrupted = False
|
39 |
-
self.
|
40 |
|
41 |
def set_api_key_queue(self, api_key_list):
|
42 |
self.multi_api_key = True
|
|
|
1 |
+
from modules.presets import CHAT_COMPLETION_URL, BALANCE_API_URL, USAGE_API_URL, API_HOST, OPENAI_API_BASE
|
2 |
import os
|
3 |
import queue
|
4 |
import openai
|
|
|
6 |
class State:
|
7 |
interrupted = False
|
8 |
multi_api_key = False
|
9 |
+
chat_completion_url = CHAT_COMPLETION_URL
|
10 |
balance_api_url = BALANCE_API_URL
|
11 |
usage_api_url = USAGE_API_URL
|
12 |
+
openai_api_base = OPENAI_API_BASE
|
13 |
|
14 |
def interrupt(self):
|
15 |
self.interrupted = True
|
|
|
23 |
api_host = f"https://{api_host}"
|
24 |
if api_host.endswith("/v1"):
|
25 |
api_host = api_host[:-3]
|
26 |
+
self.chat_completion_url = f"{api_host}/v1/chat/completions"
|
27 |
+
self.openai_api_base = f"{api_host}/v1"
|
28 |
self.balance_api_url = f"{api_host}/dashboard/billing/credit_grants"
|
29 |
self.usage_api_url = f"{api_host}/dashboard/billing/usage"
|
30 |
os.environ["OPENAI_API_BASE"] = api_host
|
31 |
|
32 |
def reset_api_host(self):
|
33 |
+
self.chat_completion_url = CHAT_COMPLETION_URL
|
34 |
self.balance_api_url = BALANCE_API_URL
|
35 |
self.usage_api_url = USAGE_API_URL
|
36 |
os.environ["OPENAI_API_BASE"] = f"https://{API_HOST}"
|
|
|
38 |
|
39 |
def reset_all(self):
|
40 |
self.interrupted = False
|
41 |
+
self.chat_completion_url = CHAT_COMPLETION_URL
|
42 |
|
43 |
def set_api_key_queue(self, api_key_list):
|
44 |
self.multi_api_key = True
|
modules/utils.py
CHANGED
@@ -68,15 +68,15 @@ def delete_last_conversation(current_model, *args):
|
|
68 |
def set_system_prompt(current_model, *args):
|
69 |
return current_model.set_system_prompt(*args)
|
70 |
|
71 |
-
def
|
72 |
-
return current_model.
|
|
|
|
|
|
|
73 |
|
74 |
def export_markdown(current_model, *args):
|
75 |
return current_model.export_markdown(*args)
|
76 |
|
77 |
-
def load_chat_history(current_model, *args):
|
78 |
-
return current_model.load_chat_history(*args)
|
79 |
-
|
80 |
def upload_chat_history(current_model, *args):
|
81 |
return current_model.load_chat_history(*args)
|
82 |
|
@@ -331,55 +331,97 @@ def construct_assistant(text):
|
|
331 |
|
332 |
|
333 |
def save_file(filename, system, history, chatbot, user_name):
|
334 |
-
logging.debug(f"{user_name} 保存对话历史中……")
|
335 |
os.makedirs(os.path.join(HISTORY_DIR, user_name), exist_ok=True)
|
336 |
-
if filename
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
351 |
return os.path.join(HISTORY_DIR, user_name, filename)
|
352 |
|
353 |
|
354 |
def sorted_by_pinyin(list):
|
355 |
return sorted(list, key=lambda char: lazy_pinyin(char)[0][0])
|
356 |
|
|
|
|
|
357 |
|
358 |
-
def
|
359 |
-
logging.debug(f"获取文件名列表,目录为{dir},文件类型为{filetypes}
|
360 |
files = []
|
361 |
-
|
362 |
-
for
|
363 |
-
files += [f for f in os.listdir(dir) if f.endswith(type)]
|
364 |
-
except FileNotFoundError:
|
365 |
-
files = []
|
366 |
-
files = sorted_by_pinyin(files)
|
367 |
-
if files == []:
|
368 |
-
files = [""]
|
369 |
logging.debug(f"files are:{files}")
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
374 |
|
375 |
|
376 |
-
def get_history_names(
|
377 |
logging.debug(f"从用户 {user_name} 中获取历史记录文件名列表")
|
378 |
if user_name == "" and hide_history_when_not_logged_in:
|
379 |
-
return
|
380 |
else:
|
381 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
382 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
383 |
|
384 |
def load_template(filename, mode=0):
|
385 |
logging.debug(f"加载模板文件{filename},模式为{mode}(0为返回字典和下拉菜单,1为返回下拉菜单,2为返回字典)")
|
@@ -406,9 +448,14 @@ def load_template(filename, mode=0):
|
|
406 |
)
|
407 |
|
408 |
|
409 |
-
def get_template_names(
|
410 |
logging.debug("获取模板文件名列表")
|
411 |
-
return
|
|
|
|
|
|
|
|
|
|
|
412 |
|
413 |
|
414 |
def get_template_content(templates, selection, original_system_prompt):
|
@@ -614,36 +661,21 @@ def toggle_like_btn_visibility(selected_model_name):
|
|
614 |
else:
|
615 |
return gr.update(visible=False)
|
616 |
|
617 |
-
def new_auto_history_filename(
|
618 |
-
latest_file =
|
619 |
if latest_file:
|
620 |
-
with open(os.path.join(
|
621 |
if len(f.read()) == 0:
|
622 |
return latest_file
|
623 |
-
now = datetime.datetime.now().strftime('%
|
624 |
return f'{now}.json'
|
625 |
|
626 |
-
def get_latest_filepath(dirname):
|
627 |
-
pattern = re.compile(r'\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}')
|
628 |
-
latest_time = None
|
629 |
-
latest_file = None
|
630 |
-
for filename in os.listdir(dirname):
|
631 |
-
if os.path.isfile(os.path.join(dirname, filename)):
|
632 |
-
match = pattern.search(filename)
|
633 |
-
if match and match.group(0) == filename[:19]:
|
634 |
-
time_str = filename[:19]
|
635 |
-
filetime = datetime.datetime.strptime(time_str, '%Y-%m-%d_%H-%M-%S')
|
636 |
-
if not latest_time or filetime > latest_time:
|
637 |
-
latest_time = filetime
|
638 |
-
latest_file = filename
|
639 |
-
return latest_file
|
640 |
-
|
641 |
def get_history_filepath(username):
|
642 |
dirname = os.path.join(HISTORY_DIR, username)
|
643 |
os.makedirs(dirname, exist_ok=True)
|
644 |
-
latest_file =
|
645 |
if not latest_file:
|
646 |
-
latest_file = new_auto_history_filename(
|
647 |
|
648 |
latest_file = os.path.join(dirname, latest_file)
|
649 |
return latest_file
|
@@ -651,7 +683,7 @@ def get_history_filepath(username):
|
|
651 |
def beautify_err_msg(err_msg):
|
652 |
if "insufficient_quota" in err_msg:
|
653 |
return i18n("剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)")
|
654 |
-
if "The model
|
655 |
return i18n("你没有权限访问 GPT4,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)")
|
656 |
if "Resource not found" in err_msg:
|
657 |
return i18n("请查看 config_example.json,配置 Azure OpenAI")
|
@@ -681,3 +713,14 @@ def get_file_hash(file_src=None, file_paths=None):
|
|
681 |
md5_hash.update(chunk)
|
682 |
|
683 |
return md5_hash.hexdigest()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
def set_system_prompt(current_model, *args):
|
69 |
return current_model.set_system_prompt(*args)
|
70 |
|
71 |
+
def rename_chat_history(current_model, *args):
|
72 |
+
return current_model.rename_chat_history(*args)
|
73 |
+
|
74 |
+
def auto_name_chat_history(current_model, *args):
|
75 |
+
return current_model.auto_name_chat_history(*args)
|
76 |
|
77 |
def export_markdown(current_model, *args):
|
78 |
return current_model.export_markdown(*args)
|
79 |
|
|
|
|
|
|
|
80 |
def upload_chat_history(current_model, *args):
|
81 |
return current_model.load_chat_history(*args)
|
82 |
|
|
|
331 |
|
332 |
|
333 |
def save_file(filename, system, history, chatbot, user_name):
|
|
|
334 |
os.makedirs(os.path.join(HISTORY_DIR, user_name), exist_ok=True)
|
335 |
+
if filename is None:
|
336 |
+
filename = new_auto_history_filename(user_name)
|
337 |
+
if filename.endswith(".md"):
|
338 |
+
filename = filename[:-3]
|
339 |
+
if not filename.endswith(".json") and not filename.endswith(".md"):
|
340 |
+
filename += ".json"
|
341 |
+
if filename == ".json":
|
342 |
+
raise Exception("文件名不能为空")
|
343 |
+
|
344 |
+
json_s = {"system": system, "history": history, "chatbot": chatbot}
|
345 |
+
repeat_file_index = 2
|
346 |
+
if not filename == os.path.basename(filename):
|
347 |
+
history_file_path = filename
|
348 |
+
else:
|
349 |
+
history_file_path = os.path.join(HISTORY_DIR, user_name, filename)
|
350 |
+
|
351 |
+
with open(history_file_path, "w", encoding='utf-8') as f:
|
352 |
+
json.dump(json_s, f, ensure_ascii=False)
|
353 |
+
|
354 |
+
filename = os.path.basename(filename)
|
355 |
+
filename_md = filename[:-5] + ".md"
|
356 |
+
md_s = f"system: \n- {system} \n"
|
357 |
+
for data in history:
|
358 |
+
md_s += f"\n{data['role']}: \n- {data['content']} \n"
|
359 |
+
with open(os.path.join(HISTORY_DIR, user_name, filename_md), "w", encoding="utf8") as f:
|
360 |
+
f.write(md_s)
|
361 |
return os.path.join(HISTORY_DIR, user_name, filename)
|
362 |
|
363 |
|
364 |
def sorted_by_pinyin(list):
|
365 |
return sorted(list, key=lambda char: lazy_pinyin(char)[0][0])
|
366 |
|
367 |
+
def sorted_by_last_modified_time(list, dir):
|
368 |
+
return sorted(list, key=lambda char: os.path.getctime(os.path.join(dir, char)), reverse=True)
|
369 |
|
370 |
+
def get_file_names_by_type(dir, filetypes=[".json"]):
|
371 |
+
logging.debug(f"获取文件名列表,目录为{dir},文件类型为{filetypes}")
|
372 |
files = []
|
373 |
+
for type in filetypes:
|
374 |
+
files += [f for f in os.listdir(dir) if f.endswith(type)]
|
|
|
|
|
|
|
|
|
|
|
|
|
375 |
logging.debug(f"files are:{files}")
|
376 |
+
return files
|
377 |
+
|
378 |
+
def get_file_names_by_pinyin(dir, filetypes=[".json"]):
|
379 |
+
files = get_file_names_by_type(dir, filetypes)
|
380 |
+
if files != [""]:
|
381 |
+
files = sorted_by_pinyin(files)
|
382 |
+
logging.debug(f"files are:{files}")
|
383 |
+
return files
|
384 |
+
|
385 |
+
def get_file_names_dropdown_by_pinyin(dir, filetypes=[".json"]):
|
386 |
+
files = get_file_names_by_pinyin(dir, filetypes)
|
387 |
+
return gr.Dropdown.update(choices=files)
|
388 |
+
|
389 |
+
def get_file_names_by_last_modified_time(dir, filetypes=[".json"]):
|
390 |
+
files = get_file_names_by_type(dir, filetypes)
|
391 |
+
if files != [""]:
|
392 |
+
files = sorted_by_last_modified_time(files, dir)
|
393 |
+
logging.debug(f"files are:{files}")
|
394 |
+
return files
|
395 |
|
396 |
|
397 |
+
def get_history_names(user_name=""):
|
398 |
logging.debug(f"从用户 {user_name} 中获取历史记录文件名列表")
|
399 |
if user_name == "" and hide_history_when_not_logged_in:
|
400 |
+
return []
|
401 |
else:
|
402 |
+
history_files = get_file_names_by_last_modified_time(os.path.join(HISTORY_DIR, user_name))
|
403 |
+
history_files = [f[:f.rfind(".")] for f in history_files]
|
404 |
+
return history_files
|
405 |
+
|
406 |
+
def get_first_history_name(user_name=""):
|
407 |
+
history_names = get_history_names(user_name)
|
408 |
+
return history_names[0] if history_names else None
|
409 |
|
410 |
+
def get_history_list(user_name=""):
|
411 |
+
history_names = get_history_names(user_name)
|
412 |
+
return gr.Radio.update(choices=history_names)
|
413 |
+
|
414 |
+
def init_history_list(user_name=""):
|
415 |
+
history_names = get_history_names(user_name)
|
416 |
+
return gr.Radio.update(choices=history_names, value=history_names[0] if history_names else "")
|
417 |
+
|
418 |
+
def filter_history(user_name, keyword):
|
419 |
+
history_names = get_history_names(user_name)
|
420 |
+
try:
|
421 |
+
history_names = [name for name in history_names if re.search(keyword, name)]
|
422 |
+
return gr.update(choices=history_names)
|
423 |
+
except:
|
424 |
+
return gr.update(choices=history_names)
|
425 |
|
426 |
def load_template(filename, mode=0):
|
427 |
logging.debug(f"加载模板文件{filename},模式为{mode}(0为返回字典和下拉菜单,1为返回下拉菜单,2为返回字典)")
|
|
|
448 |
)
|
449 |
|
450 |
|
451 |
+
def get_template_names():
|
452 |
logging.debug("获取模板文件名列表")
|
453 |
+
return get_file_names_by_pinyin(TEMPLATES_DIR, filetypes=[".csv", "json"])
|
454 |
+
|
455 |
+
def get_template_dropdown():
|
456 |
+
logging.debug("获取模板下拉菜单")
|
457 |
+
template_names = get_template_names()
|
458 |
+
return gr.Dropdown.update(choices=template_names)
|
459 |
|
460 |
|
461 |
def get_template_content(templates, selection, original_system_prompt):
|
|
|
661 |
else:
|
662 |
return gr.update(visible=False)
|
663 |
|
664 |
+
def new_auto_history_filename(username):
|
665 |
+
latest_file = get_first_history_name(username)
|
666 |
if latest_file:
|
667 |
+
with open(os.path.join(HISTORY_DIR, username, latest_file + ".json"), 'r', encoding="utf-8") as f:
|
668 |
if len(f.read()) == 0:
|
669 |
return latest_file
|
670 |
+
now = i18n("新对话 ") + datetime.datetime.now().strftime('%m-%d %H-%M')
|
671 |
return f'{now}.json'
|
672 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
673 |
def get_history_filepath(username):
|
674 |
dirname = os.path.join(HISTORY_DIR, username)
|
675 |
os.makedirs(dirname, exist_ok=True)
|
676 |
+
latest_file = get_first_history_name(username)
|
677 |
if not latest_file:
|
678 |
+
latest_file = new_auto_history_filename(username)
|
679 |
|
680 |
latest_file = os.path.join(dirname, latest_file)
|
681 |
return latest_file
|
|
|
683 |
def beautify_err_msg(err_msg):
|
684 |
if "insufficient_quota" in err_msg:
|
685 |
return i18n("剩余配额不足,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98#you-exceeded-your-current-quota-please-check-your-plan-and-billing-details)")
|
686 |
+
if "The model `gpt-4` does not exist" in err_msg:
|
687 |
return i18n("你没有权限访问 GPT4,[进一步了解](https://github.com/GaiZhenbiao/ChuanhuChatGPT/issues/843)")
|
688 |
if "Resource not found" in err_msg:
|
689 |
return i18n("请查看 config_example.json,配置 Azure OpenAI")
|
|
|
713 |
md5_hash.update(chunk)
|
714 |
|
715 |
return md5_hash.hexdigest()
|
716 |
+
|
717 |
+
def myprint(**args):
|
718 |
+
print(args)
|
719 |
+
|
720 |
+
def replace_special_symbols(string, replace_string=" "):
|
721 |
+
# 定义正则表达式,匹配所有特殊符号
|
722 |
+
pattern = r'[!@#$%^&*()<>?/\|}{~:]'
|
723 |
+
|
724 |
+
new_string = re.sub(pattern, replace_string, string)
|
725 |
+
|
726 |
+
return new_string
|
modules/webui.py
CHANGED
@@ -56,11 +56,24 @@ def reload_javascript():
|
|
56 |
js += '<script async type="module" src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>'
|
57 |
js += '<script async type="module" src="http://spin.js.org/spin.umd.js"></script><link type="text/css" href="https://spin.js.org/spin.css" rel="stylesheet" />'
|
58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
css = css_html()
|
60 |
|
61 |
def template_response(*args, **kwargs):
|
62 |
res = GradioTemplateResponseOriginal(*args, **kwargs)
|
63 |
-
res.body = res.body.replace(b'</head>', f'{js}</head>'.encode("utf8"))
|
|
|
64 |
res.body = res.body.replace(b'</body>', f'{css}</body>'.encode("utf8"))
|
65 |
res.init_headers()
|
66 |
return res
|
|
|
56 |
js += '<script async type="module" src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>'
|
57 |
js += '<script async type="module" src="http://spin.js.org/spin.umd.js"></script><link type="text/css" href="https://spin.js.org/spin.css" rel="stylesheet" />'
|
58 |
|
59 |
+
meta = """
|
60 |
+
<meta name="apple-mobile-web-app-title" content="川虎 Chat">
|
61 |
+
<meta name="apple-mobile-web-app-capable" content="yes">
|
62 |
+
<meta name="application-name" content="川虎 Chat">
|
63 |
+
<meta name='viewport' content='width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover'>
|
64 |
+
<meta name="theme-color" content="#ffffff">
|
65 |
+
|
66 |
+
<link rel="apple-touch-icon-precomposed" href="/file=web_assets/icon/mask-icon-512.png" crossorigin="use-credentials">
|
67 |
+
<link rel="apple-touch-icon" href="/file=web_assets/icon/mask-icon-512.png" crossorigin="use-credentials">
|
68 |
+
|
69 |
+
<link rel="manifest" href="/file=web_assets/manifest.json" crossorigin="use-credentials">
|
70 |
+
"""
|
71 |
css = css_html()
|
72 |
|
73 |
def template_response(*args, **kwargs):
|
74 |
res = GradioTemplateResponseOriginal(*args, **kwargs)
|
75 |
+
res.body = res.body.replace(b'</head>', f'{meta}{js}</head>'.encode("utf8"))
|
76 |
+
# res.body = res.body.replace(b'</head>', f'{js}</head>'.encode("utf8"))
|
77 |
res.body = res.body.replace(b'</body>', f'{css}</body>'.encode("utf8"))
|
78 |
res.init_headers()
|
79 |
return res
|
modules/webui_locale.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
import os
|
2 |
import locale
|
|
|
3 |
import commentjson as json
|
4 |
|
5 |
class I18nAuto:
|
@@ -9,8 +10,9 @@ class I18nAuto:
|
|
9 |
config = json.load(f)
|
10 |
else:
|
11 |
config = {}
|
12 |
-
|
13 |
-
language = os.environ.get("LANGUAGE",
|
|
|
14 |
if language == "auto":
|
15 |
language = locale.getdefaultlocale()[0] # get the language code of the system (ex. zh_CN)
|
16 |
self.language_map = {}
|
@@ -18,6 +20,11 @@ class I18nAuto:
|
|
18 |
if self.file_is_exists:
|
19 |
with open(f"./locale/{language}.json", "r", encoding="utf-8") as f:
|
20 |
self.language_map.update(json.load(f))
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
def __call__(self, key):
|
23 |
if self.file_is_exists and key in self.language_map:
|
|
|
1 |
import os
|
2 |
import locale
|
3 |
+
import logging
|
4 |
import commentjson as json
|
5 |
|
6 |
class I18nAuto:
|
|
|
10 |
config = json.load(f)
|
11 |
else:
|
12 |
config = {}
|
13 |
+
language = config.get("language", "auto")
|
14 |
+
language = os.environ.get("LANGUAGE", language)
|
15 |
+
language = language.replace("-", "_")
|
16 |
if language == "auto":
|
17 |
language = locale.getdefaultlocale()[0] # get the language code of the system (ex. zh_CN)
|
18 |
self.language_map = {}
|
|
|
20 |
if self.file_is_exists:
|
21 |
with open(f"./locale/{language}.json", "r", encoding="utf-8") as f:
|
22 |
self.language_map.update(json.load(f))
|
23 |
+
else:
|
24 |
+
logging.warning(f"Language file for {language} does not exist. Using English instead.")
|
25 |
+
logging.warning(f"Available languages: {', '.join([x[:-5] for x in os.listdir('./locale')])}")
|
26 |
+
with open(f"./locale/en_US.json", "r", encoding="utf-8") as f:
|
27 |
+
self.language_map.update(json.load(f))
|
28 |
|
29 |
def __call__(self, key):
|
30 |
if self.file_is_exists and key in self.language_map:
|
readme/README_en.md
CHANGED
@@ -1,6 +1,6 @@
|
|
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>
|
@@ -22,11 +22,7 @@
|
|
22 |
<img alt="GitHub pull requests" src="https://img.shields.io/badge/Telegram-Group-blue.svg?logo=telegram" />
|
23 |
</a>
|
24 |
<p>
|
25 |
-
|
26 |
-
LaTeX rendering / Table rendering / Code highlighting <br />
|
27 |
-
Auto dark mode / Adaptive web interface / WeChat-like theme <br />
|
28 |
-
Multi-parameters tuning / Multi-API-Key support / Multi-user support <br />
|
29 |
-
Compatible with GPT-4 / Local deployment for LLMs
|
30 |
</p>
|
31 |
<a href="https://www.youtube.com/watch?v=MtxS4XZWbJE"><strong>Video Tutorial</strong></a>
|
32 |
·
|
@@ -38,41 +34,94 @@
|
|
38 |
·
|
39 |
<a href="https://huggingface.co/login?next=%2Fspaces%2FJohnSmith9982%2FChuanhuChatGPT%3Fduplicate%3Dtrue"><strong>One-Click deployment</strong></a>
|
40 |
</p>
|
41 |
-
<p align="center">
|
42 |
-
<img alt="Animation Demo" src="https://user-images.githubusercontent.com/51039745/226255695-6b17ff1f-ea8d-464f-b69b-a7b6b68fffe8.gif" />
|
43 |
-
</p>
|
44 |
</p>
|
45 |
</div>
|
46 |
|
47 |
-
|
48 |
|
49 |
-
|
50 |
|
51 |
-
|
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 |
-
|
60 |
-
- [LLaMA](https://github.com/facebookresearch/llama)
|
61 |
-
- [StableLM](https://github.com/Stability-AI/StableLM)
|
62 |
-
- [MOSS](https://github.com/OpenLMLab/MOSS)
|
63 |
|
64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
|
66 |
-
|
67 |
-
- To use a Prompt Template, select the Prompt Template Collection file first, and then choose certain prompt from the drop-down menu.
|
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, set `"server_name": "0.0.0.0", "server_port" <your port number>,` in `config.json`.
|
72 |
-
- To get a public shared link, set `"share": true,` in `config.json`. Please be noted that the program must be running in order to be accessed via a public 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
|
@@ -86,21 +135,22 @@ Then make a copy of `config_example.json`, rename it to `config.json`, and then
|
|
86 |
python ChuanhuChatbot.py
|
87 |
```
|
88 |
|
89 |
-
A browser window will open
|
90 |
|
91 |
> **Note**
|
92 |
>
|
93 |
-
> Please check our [wiki page](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程) for detailed instructions.
|
|
|
94 |
|
95 |
## Troubleshooting
|
96 |
|
97 |
-
When you encounter problems, you should try manually
|
98 |
|
99 |
-
1.
|
100 |
```shell
|
101 |
git pull https://github.com/GaiZhenbiao/ChuanhuChatGPT.git main -f
|
102 |
```
|
103 |
-
2. Try
|
104 |
```
|
105 |
pip install -r requirements.txt
|
106 |
```
|
|
|
1 |
<div align="right">
|
2 |
<!-- Language: -->
|
3 |
+
<a title="Chinese" href="../README.md">简体中文</a> | English | <a title="Japanese" href="README_ja.md">日本語</a> | <a title="Russian" href="README_ru.md">Russian</a>
|
4 |
</div>
|
5 |
|
6 |
<h1 align="center">川虎 Chat 🐯 Chuanhu Chat</h1>
|
|
|
22 |
<img alt="GitHub pull requests" src="https://img.shields.io/badge/Telegram-Group-blue.svg?logo=telegram" />
|
23 |
</a>
|
24 |
<p>
|
25 |
+
Compatible with GPT-4 · Chat with files · LLMs local deployment · Web search · Chuanhu Agent · Fine-tuning
|
|
|
|
|
|
|
|
|
26 |
</p>
|
27 |
<a href="https://www.youtube.com/watch?v=MtxS4XZWbJE"><strong>Video Tutorial</strong></a>
|
28 |
·
|
|
|
34 |
·
|
35 |
<a href="https://huggingface.co/login?next=%2Fspaces%2FJohnSmith9982%2FChuanhuChatGPT%3Fduplicate%3Dtrue"><strong>One-Click deployment</strong></a>
|
36 |
</p>
|
|
|
|
|
|
|
37 |
</p>
|
38 |
</div>
|
39 |
|
40 |
+
[![Video Title](https://github.com/GaiZhenbiao/ChuanhuChatGPT/assets/51039745/0eee1598-c2fd-41c6-bda9-7b059a3ce6e7.jpg)](https://github.com/GaiZhenbiao/ChuanhuChatGPT/assets/51039745/0eee1598-c2fd-41c6-bda9-7b059a3ce6e7?autoplay=1)
|
41 |
|
42 |
+
## ✨ 5.0 Major Update!
|
43 |
|
44 |
+
![ChuanhuChat5update](https://github.com/GaiZhenbiao/ChuanhuChatGPT/assets/70903329/f2c2be3a-ea93-4edf-8221-94eddd4a0178)
|
|
|
|
|
|
|
|
|
45 |
|
|
|
46 |
|
47 |
+
<sup>New!</sup> An all-new user interface! So exquisite that it doesn't look like Gradio, it even has a frosted glass effect!
|
|
|
|
|
|
|
48 |
|
49 |
+
<sup>New!</sup> Adapted for mobile devices (including perforated/bezel-less phones), the hierarchy is clearer.
|
50 |
+
|
51 |
+
<sup>New!</sup> The history is moved to the left for easier use. And supports search (with regular expressions), delete, and rename.
|
52 |
+
|
53 |
+
<sup>New!</sup> Now you can let the large model automatically name the history (Enabled in the settings or configuration file).
|
54 |
+
|
55 |
+
<sup>New!</sup> Chuanhu Chat can now be installed as a PWA application for a more native experience! Supported on Chrome/Edge/Safari etc.
|
56 |
|
57 |
+
<sup>New!</sup> Icons adapted for all platforms, looking more comfortable.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
|
59 |
+
<sup>New!</sup> Supports Finetune (fine-tuning) GPT 3.5!
|
60 |
+
|
61 |
+
## Supported Models
|
62 |
+
|
63 |
+
| API Callable Models | Remarks | Locally Deployed Models | Remarks |
|
64 |
+
| :---: | --- | :---: | --- |
|
65 |
+
| [ChatGPT(GPT-4)](https://chat.openai.com) | Support fine-tune gpt-3.5 | [ChatGLM](https://github.com/THUDM/ChatGLM-6B) ([ChatGLM2](https://github.com/THUDM/ChatGLM2-6B)) |
|
66 |
+
| [Azure OpenAI](https://azure.microsoft.com/en-us/products/ai-services/openai-service) | | [LLaMA](https://github.com/facebookresearch/llama) | Support Lora models
|
67 |
+
| [Google PaLM](https://developers.generativeai.google/products/palm) | Not support streaming | [StableLM](https://github.com/Stability-AI/StableLM)
|
68 |
+
| [iFlytek Starfire Cognition Large Model](https://xinghuo.xfyun.cn) | | [MOSS](https://github.com/OpenLMLab/MOSS)
|
69 |
+
| [Inspur Yuan 1.0](https://air.inspur.com/home) | | [Qwen](https://github.com/QwenLM/Qwen/tree/main)
|
70 |
+
| [MiniMax](https://api.minimax.chat/) |
|
71 |
+
| [XMChat](https://github.com/MILVLG/xmchat) | Not support streaming
|
72 |
+
| [Midjourney](https://www.midjourney.com/) | Not support streaming
|
73 |
+
| [Claude](https://www.anthropic.com/) |
|
74 |
+
|
75 |
+
## Usage Tips
|
76 |
+
|
77 |
+
### 💪 Powerful Functions
|
78 |
+
- **Chuanhu Assistant**: Similar to AutoGPT, automatically solves your problems;
|
79 |
+
- **Online Search**: Is ChatGPT's data too old? Give LLM the wings of the internet;
|
80 |
+
- **Knowledge Base**: Let ChatGPT help you speed read quantumly! Answer questions based on files.
|
81 |
+
- **Local LLM Deployment**: One-click deployment, get your own large language model.
|
82 |
+
|
83 |
+
### 🤖 System Prompt
|
84 |
+
- The system prompt can effectively enable role-playing by setting prerequisite conditions;
|
85 |
+
- ChuanhuChat presets Prompt templates, click `Load Prompt Template`, choose the Prompt template collection first, then choose the Prompt you want in the list below.
|
86 |
+
|
87 |
+
### 💬 Basic Conversation
|
88 |
+
- If the answer is not satisfactory, you can try the `Regenerate` button again, or directly `Delete this round of conversation`;
|
89 |
+
- Input box supports line breaks, press <kbd>Shift</kbd> + <kbd>Enter</kbd> to make one;
|
90 |
+
- Using the <kbd>↑</kbd> <kbd>↓</kbd> arrow keys in the input box, you can quickly switch between send records;
|
91 |
+
- Generating a new conversation every time is too cumbersome, try the `single-dialogue` function;
|
92 |
+
- The small button next to the answer bubble not only allows `one-click copy`, but also lets you `view the original Markdown text`;
|
93 |
+
- Specify the answer language, so that ChatGPT will always reply in a certain language.
|
94 |
+
|
95 |
+
### 📜 Chat History
|
96 |
+
- Dialogue history will be automatically saved, you won't have to worry about not being able to find it after asking;
|
97 |
+
- Multi-user history isolation, only you can see them;
|
98 |
+
- Rename chat, easy to find in the future;
|
99 |
+
- <sup>New!</sup> Magically auto-name the chat, let LLM understand the conversation content, and automatically name the chat for you!
|
100 |
+
- <sup>New!</sup> Search chat, supports regular expressions!
|
101 |
+
|
102 |
+
### 🖼️ Small and Beautiful Experience
|
103 |
+
- Self-developed Small-and-Beautiful theme, gives you a small and beautiful experience;
|
104 |
+
- Automatic light and dark color switching, gives you a comfortable experience from morning till night;
|
105 |
+
- Perfectly rendering LaTeX / tables / code blocks, supports code highlighting;
|
106 |
+
- <sup>New!</sup> Non-linear animations, frosted glass effect, so exquisite it doesn't look like Gradio!
|
107 |
+
- <sup>New!</sup> Adapted for Windows / macOS / Linux / iOS / Android, from icon to screen adaptation, gives you the most suitable experience!
|
108 |
+
- <sup>New!</sup> Supports PWA app installation for an even more native experience!
|
109 |
+
|
110 |
+
### 👨💻 Geek Functions
|
111 |
+
- <sup>New!</sup> Supports Fine-tuning gpt-3.5!
|
112 |
+
- Plenty of available LLM parameters to adjust;
|
113 |
+
- Supports API-host switching;
|
114 |
+
- Supports custom proxies;
|
115 |
+
- Supports multiple api-key load balancing.
|
116 |
+
|
117 |
+
### ⚒️ Deployment Related
|
118 |
+
- Deployment to the server: Set in `config.json` `"server_name": "0.0.0.0", "server_port": <your port number>,`.
|
119 |
+
- Obtain public link: Set in `config.json` `"share": true,`. Note that the program must be running to access it through public links.
|
120 |
+
- Use on Hugging Face: It's recommended to **Duplicate the Space** in the top right corner before using, the App response might be faster.
|
121 |
+
|
122 |
+
## Quick Start
|
123 |
+
|
124 |
+
Execute the following commands in the terminal:
|
125 |
|
126 |
```shell
|
127 |
git clone https://github.com/GaiZhenbiao/ChuanhuChatGPT.git
|
|
|
135 |
python ChuanhuChatbot.py
|
136 |
```
|
137 |
|
138 |
+
A browser window will automatically open, at this point you can use **Chuanhu Chat** to chat with ChatGPT or other models.
|
139 |
|
140 |
> **Note**
|
141 |
>
|
142 |
+
> Please check our [wiki page](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程) for detailed instructions.).
|
143 |
+
|
144 |
|
145 |
## Troubleshooting
|
146 |
|
147 |
+
When you encounter problems, you should try to **manually pull the latest changes<sup>1</sup>** and **update dependencies<sup>2</sup>** first, then retry. Steps are:
|
148 |
|
149 |
+
1. Click on the `Download ZIP` button on the website, download the latest code and unzip to replace, or
|
150 |
```shell
|
151 |
git pull https://github.com/GaiZhenbiao/ChuanhuChatGPT.git main -f
|
152 |
```
|
153 |
+
2. Try to install dependencies again (the project might have new dependencies)
|
154 |
```
|
155 |
pip install -r requirements.txt
|
156 |
```
|
readme/README_ja.md
CHANGED
@@ -1,6 +1,6 @@
|
|
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>
|
@@ -22,11 +22,7 @@
|
|
22 |
<img alt="GitHub pull requests" src="https://img.shields.io/badge/Telegram-Group-blue.svg?logo=telegram" />
|
23 |
</a>
|
24 |
<p>
|
25 |
-
|
26 |
-
ウェブ検索/LaTeXレンダリング/表レンダリング/コードハイライト<br>
|
27 |
-
オートダークモード/アダプティブ・ウェブ・インターフェイス/WeChatライク・テーマ<br />
|
28 |
-
マルチパラメーターチューニング/マルチAPI-Key対応/マルチユーザー対応<br>
|
29 |
-
GPT-4対応/LLMのローカルデプロイ可能。
|
30 |
</p>
|
31 |
<a href="https://www.youtube.com/watch?v=MtxS4XZWbJE"><strong>動画チュートリアル</strong></a>
|
32 |
·
|
@@ -38,38 +34,90 @@
|
|
38 |
·
|
39 |
<a href="https://huggingface.co/login?next=%2Fspaces%2FJohnSmith9982%2FChuanhuChatGPT%3Fduplicate%3Dtrue"><strong>ワンクリックデプロイ</strong></a>
|
40 |
</p>
|
41 |
-
<p align="center">
|
42 |
-
<img alt="Animation Demo" src="https://user-images.githubusercontent.com/51039745/226255695-6b17ff1f-ea8d-464f-b69b-a7b6b68fffe8.gif" />
|
43 |
-
</p>
|
44 |
</p>
|
45 |
</div>
|
46 |
|
47 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
|
49 |
-
|
50 |
|
51 |
-
|
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 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
|
64 |
## 使う上でのTips
|
65 |
|
66 |
-
|
67 |
-
-
|
68 |
-
-
|
69 |
-
-
|
70 |
-
-
|
71 |
-
|
72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
|
74 |
## クイックスタート
|
75 |
|
|
|
1 |
<div align="right">
|
2 |
<!-- Language: -->
|
3 |
+
<a title="Chinese" href="../README.md">简体中文</a> | <a title="English" href="README_en.md">English</a> | 日本語 | <a title="Russian" href="README_ru.md">Russian</a>
|
4 |
</div>
|
5 |
|
6 |
<h1 align="center">川虎 Chat 🐯 Chuanhu Chat</h1>
|
|
|
22 |
<img alt="GitHub pull requests" src="https://img.shields.io/badge/Telegram-Group-blue.svg?logo=telegram" />
|
23 |
</a>
|
24 |
<p>
|
25 |
+
GPT-4対応 · ファイルへの質問チャット · LLMのローカルデプロイ可能 · ウェブ検索 · エージェントアシスタント · Fine-tuneをサポートします
|
|
|
|
|
|
|
|
|
26 |
</p>
|
27 |
<a href="https://www.youtube.com/watch?v=MtxS4XZWbJE"><strong>動画チュートリアル</strong></a>
|
28 |
·
|
|
|
34 |
·
|
35 |
<a href="https://huggingface.co/login?next=%2Fspaces%2FJohnSmith9982%2FChuanhuChatGPT%3Fduplicate%3Dtrue"><strong>ワンクリックデプロイ</strong></a>
|
36 |
</p>
|
|
|
|
|
|
|
37 |
</p>
|
38 |
</div>
|
39 |
|
40 |
+
[![Video Title](https://github.com/GaiZhenbiao/ChuanhuChatGPT/assets/51039745/0eee1598-c2fd-41c6-bda9-7b059a3ce6e7.jpg)](https://github.com/GaiZhenbiao/ChuanhuChatGPT/assets/51039745/0eee1598-c2fd-41c6-bda9-7b059a3ce6e7?autoplay=1)
|
41 |
+
|
42 |
+
## ✨ 5.0の重要な更新!
|
43 |
+
|
44 |
+
![ChuanhuChat5更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/assets/70903329/f2c2be3a-ea93-4edf-8221-94eddd4a0178)
|
45 |
+
|
46 |
+
<sup>新!</sup> 全く新しいユーザーインターフェース!Gradioに比べて精緻で、さらにフロストガラス効果があります!
|
47 |
|
48 |
+
<sup>新!</sup> モバイル端末(画面全体のスマホのパンチホール/ノッチを含む)に対応し、レイヤーがはっきりしてきました。
|
49 |
|
50 |
+
<sup>新!</sup> 履歴が左側に移動し、使いやすくなりました。また、検索(正規表現対応)、削除、リネームが可能です。
|
|
|
|
|
|
|
|
|
51 |
|
52 |
+
<sup>新!</sup> 大きなモデルによる履歴の自動命名が可能になりました(設定または設定ファイルで有効化が必要)。
|
53 |
|
54 |
+
<sup>新!</sup> 今では 川虎チャット を PWAアプリケーションとしてインストールすることも可能で、よりネイティブな体験ができます!Chrome/Edge/Safariなどのブラウザをサポート。
|
55 |
+
|
56 |
+
<sup>新!</sup> 各プラットフォームに適したアイコンで、見ていても気持ちがいい。
|
57 |
+
|
58 |
+
<sup>新!</sup> Finetune(微調整)GPT 3.5に対応!
|
59 |
+
|
60 |
+
## モデルのサポート
|
61 |
+
|
62 |
+
| API呼び出しモデル | 備考 | ローカルデプロイモデル | 備考 |
|
63 |
+
| :---: | --- | :---: | --- |
|
64 |
+
| [ChatGPT(GPT-4)](https://chat.openai.com) | gpt-3.5の微調整をサポート | [ChatGLM](https://github.com/THUDM/ChatGLM-6B) ([ChatGLM2](https://github.com/THUDM/ChatGLM2-6B)) |
|
65 |
+
| [Azure OpenAI](https://azure.microsoft.com/en-us/products/ai-services/openai-service) | | [LLaMA](https://github.com/facebookresearch/llama) | Loraモデルのサポートあり
|
66 |
+
| [Google PaLM](https://developers.generativeai.google/products/palm) | ストリーミング転送はサポートされていません | [StableLM](https://github.com/Stability-AI/StableLM)
|
67 |
+
| [讯飞星火认知大模型](https://xinghuo.xfyun.cn) | | [MOSS](https://github.com/OpenLMLab/MOSS)
|
68 |
+
| [Inspur Yuan 1.0](https://air.inspur.com/home) | | [Qwen](https://github.com/QwenLM/Qwen/tree/main)
|
69 |
+
| [MiniMax](https://api.minimax.chat/) |
|
70 |
+
| [XMChat](https://github.com/MILVLG/xmchat) | ストリーミング転送はサポー��されていません
|
71 |
+
| [Midjourney](https://www.midjourney.com/) | ストリーミング転送はサポートされていません
|
72 |
+
| [Claude](https://www.anthropic.com/) |
|
73 |
|
74 |
## 使う上でのTips
|
75 |
|
76 |
+
### 💪 パワフルな機能
|
77 |
+
- **川虎助理**:AutoGPTに似ており、自動的に問題を解決します。
|
78 |
+
- **オンライン検索**:ChatGPTのデータが古い場合は、LLMにネットワークの翼を付けます。
|
79 |
+
- **ナレッジベース**:ChatGPTがあなたをクイックリーディングの世界へご招待!ファイルに基づいて質問に答えます。
|
80 |
+
- **LLMのローカルデプロイ**:ワンクリックであなた自身の大規模言語モデルをデプロイします。
|
81 |
+
|
82 |
+
### 🤖 システムプロンプト
|
83 |
+
- システムプロンプトを使用して前提条件を設定すると、ロールプレイが効果的に行えます。
|
84 |
+
- 川虎Chatはプロンプトテンプレートを予め設定しており、「プロンプトテンプレートを読み込む」をクリックして、まずプロンプトテンプレートコレクションを選択し、次に下部で希望のプロンプトを選択します。
|
85 |
+
|
86 |
+
### 💬 ベーシックな対話
|
87 |
+
- もし回答が満足できない場合、「再生成」ボタンを使用して再試行するか、直接「このラウンドの対話を削除」することができます。
|
88 |
+
- 入力ボックスは改行をサポートしており、 <kbd>Shift</kbd> + <kbd>Enter</kbd> を押すと改行できます。
|
89 |
+
- 入力ボックスで <kbd>↑</kbd> <kbd>↓</kbd> キーを押すと、送信履歴をスピーディに切り替えることができます。
|
90 |
+
- 各対話を新しく作成するのは面倒ですか?「単発対話」機能を試してみてください。
|
91 |
+
- 回答バブルの横の小さなボタンは「一括コピー」だけでなく、「Markdownの元のテキストを表示」もできます。
|
92 |
+
- 回答の言語を指定して、ChatGPTが特定の言語で回答するようにします。
|
93 |
+
|
94 |
+
### 📜 履歴記録
|
95 |
+
- ダイアログの履歴は自動的に保存されるので、完了後に見つけることができます。
|
96 |
+
- 複数のユーザーの履歴は分離されており、他のユーザーは閲覧できません。
|
97 |
+
- 履歴の名前を変更することで、将来的な検索を容易にします。
|
98 |
+
- <sup>新!</sup> マジカルな自動履歴名付け機能で、LLMが対話内容を理解し、履歴に自動的に名前をつけてくれます!
|
99 |
+
- <sup>新!</sup> 正規表現をサポートする履歴検索!
|
100 |
+
|
101 |
+
### 🖼️ シンプルな使いやすさ
|
102 |
+
- 独自のSmall-and-Beautifulテーマで、シンプルで美しい体験を提供します。
|
103 |
+
- 自動的な明暗の切り替えで、早朝から夜まで快適な体験ができます。
|
104 |
+
- LaTeX/テーブル/コードブロックを完璧にレンダリングし、コードハイライトがサポートされています。
|
105 |
+
- <sup>新!</sup> ノンリニアアニメーション、フロストガラスの効果など、Gradioのように洗練されています!
|
106 |
+
- <sup>新!</sup> Windows / macOS / Linux / iOS / Androidに対応し、アイコンからフルスクリーンまで、最適な体験を提供します!
|
107 |
+
- <sup>新!</sup> PWAアプリケーションのインストールがサポートされており、よりネイティブな体験ができます!
|
108 |
+
|
109 |
+
### 👨💻 ギーク向け機能
|
110 |
+
- <sup>新!</sup> gpt-3.5のFine-tune(微調整)がサポートされています!
|
111 |
+
- 多くのLLMパラメータをカスタマイズできます。
|
112 |
+
- api-hostの変更が可能です。
|
113 |
+
- カスタムプロキシの設定が可能です。
|
114 |
+
- 負荷分散のための複数のapiキーのサポートがあります。
|
115 |
+
|
116 |
+
### ⚒️ デプ���イに関する情報
|
117 |
+
- サーバーへのデプロイ:`config.json`ファイルで`"server_name": "0.0.0.0", "server_port": <あなたのポート番号>,"`を設定します。
|
118 |
+
- 共有リンクの取得:`config.json`ファイルで`"share": true,`を設定します。ただし、プログラムが実行されている必要があります。
|
119 |
+
- Hugging Faceでの使用:右上のコーナーの「Spaceをコピー」を選択し、それから使用することをおすすめします。これにより、アプリの反応が速くなる場合があります。
|
120 |
+
|
121 |
|
122 |
## クイックスタート
|
123 |
|
readme/README_ru.md
ADDED
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div align="right">
|
2 |
+
<!-- Language: -->
|
3 |
+
<a title="Chinese" href="../README.md">简体中文</a> | <a title="English" href="README_en.md">English</a> | <a title="Japanese" href="README_ja.md">日本語</a> | Russian
|
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>Легкий и удобный веб-интерфейс для LLM, включая ChatGPT/ChatGLM/LLaMA</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 |
+
Поддержка GPT-4 · Анализ файлов в чате · Локальная установка LLM · Онлайн-поиск · Помощник Agent · Поддержка Fine-tune
|
26 |
+
</p>
|
27 |
+
<a href="https://www.youtube.com/watch?v=MtxS4XZWbJE"><strong>Видео туториал</strong></a>
|
28 |
+
·
|
29 |
+
<a href="https://www.youtube.com/watch?v=77nw7iimYDE"><strong>2.0 Введение</strong></a>
|
30 |
+
·
|
31 |
+
<a href="https://www.youtube.com/watch?v=x-O1jjBqgu4"><strong>3.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>
|
38 |
+
</div>
|
39 |
+
|
40 |
+
[![Video Title](https://github.com/GaiZhenbiao/ChuanhuChatGPT/assets/51039745/0eee1598-c2fd-41c6-bda9-7b059a3ce6e7.jpg)](https://github.com/GaiZhenbiao/ChuanhuChatGPT/assets/51039745/0eee1598-c2fd-41c6-bda9-7b059a3ce6e7?autoplay=1)
|
41 |
+
|
42 |
+
## ✨ Обновление 5.0!
|
43 |
+
|
44 |
+
![ChuanhuChat5](https://github.com/GaiZhenbiao/ChuanhuChatGPT/assets/70903329/f2c2be3a-ea93-4edf-8221-94eddd4a0178)
|
45 |
+
|
46 |
+
<sup>New!</sup> Совершенно новый пользовательский интерфейс! Он такой приятный, не похожий на Gradio, с новым эффектом матового стекла!
|
47 |
+
|
48 |
+
<sup>New!</sup> Адаптация для мобильных устройств (включая экраны с отверстием/выемкой под камеру), иерархия стала более четкой.
|
49 |
+
|
50 |
+
<sup>New!</sup> История перенесена в левую часть для удобства использования. Поддерживается поиск (с поддержкой регулярных выражений), удаление и переименование.
|
51 |
+
|
52 |
+
<sup>New!</sup> Теперь можно автоматически давать истории имена для больших моделей (требуется включение в настройках или в конфигурационном файле).
|
53 |
+
|
54 |
+
<sup>New!</sup> Теперь можно установить Чуаньху Чат в качестве приложения PWA, чтобы повысить нативность! Поддерживаемые браузеры: Chrome/Edge/Safari и другие.
|
55 |
+
|
56 |
+
<sup>New!</sup> Значок адаптирован для различных платформ, выглядит более комфортно.
|
57 |
+
|
58 |
+
<sup>New!</sup> Поддержка Fine-tune (микронной настройки) GPT 3.5!
|
59 |
+
|
60 |
+
## Поддерживаемые модели
|
61 |
+
|
62 |
+
| Модель с использованием API | Примечание | Локально развернутые модели | Примечание |
|
63 |
+
| :---: | --- | :---: | --- |
|
64 |
+
| [ChatGPT (GPT-4)](https://chat.openai.com) | Поддерживает микронастройку gpt-3.5 | [ChatGLM](https://github.com/THUDM/ChatGLM-6B) ([ChatGLM2](https://github.com/THUDM/ChatGLM2-6B)) |
|
65 |
+
| [Azure OpenAI](https://azure.microsoft.com/en-us/products/ai-services/openai-service) | | [LLaMA](https://github.com/facebookresearch/llama) | Поддерживает модель Lora
|
66 |
+
| [Google PaLM](https://developers.generativeai.google/products/palm) | Не поддерживает потоковую передачу данных | [StableLM](https://github.com/Stability-AI/StableLM)
|
67 |
+
| [Xunfei Xinghuo Cognitive Model](https://xinghuo.xfyun.cn) | | [MOSS](https://github.com/OpenLMLab/MOSS)
|
68 |
+
| [Inspur Yuan 1.0](https://air.inspur.com/home) | | [Qwen](https://github.com/QwenLM/Qwen/tree/main)
|
69 |
+
| [MiniMax](https://api.minimax.chat/) |
|
70 |
+
| [XMChat](https://github.com/MILVLG/xmchat) | Не поддерживает потоковую передачу данных
|
71 |
+
| [Midjourney](https://www.midjourney.com/) | Не поддерживает потоковую передачу данных
|
72 |
+
| [Claude](https://www.anthropic.com/) |
|
73 |
+
|
74 |
+
## Советы по использованию
|
75 |
+
|
76 |
+
### 💪 Мощные функции
|
77 |
+
- **Chuanhu ассистент**: подобно AutoGPT, полностью автоматизированное решение вашей проблемы;
|
78 |
+
- **Поиск в Интернете**: данные ChatGPT устарели? Дайте LLM возможность использовать сеть;
|
79 |
+
- **База знаний**: позвольте ChatGPT помочь вам быстро прочитать информацию! Ответить на вопросы в соответствии с файлами.
|
80 |
+
- **Локальная установка LLM**: одним щелчком разверните свою собственную модель языка большого размера.
|
81 |
+
|
82 |
+
### 🤖 Системный промт
|
83 |
+
- Установка предпосылок через системное сообщение позволяет эффективно играть роль персонажа;
|
84 |
+
- Чуаньху Чат предоставляет набор системных шаблонов, нажмите "Загрузить шаблон системного сообщения", затем выберите необходимый шаблон ниже.
|
85 |
+
|
86 |
+
### 💬 Обычный диалог
|
87 |
+
- Если ответ не удовлетворяет вас, можно попробовать снова с помощью кнопки "Перегенерировать" или просто удалить этот раунд диалога;
|
88 |
+
- Поле ввода поддерживает перенос строки, нажмите <kbd>Shift</kbd> + <kbd>Enter</kbd>, чтобы сделать перенос строки;
|
89 |
+
- В поле ввода можно использовать клавиши <kbd>↑</kbd> и <kbd>↓</kbd>, чтобы быстро переключаться в истории отправки;
|
90 |
+
- Создание нового диалога слишком неудобно? Попробуйте функцию "Одиночный диалог";
|
91 |
+
- У кнопки возле пузыря с ответом можно не только "скопировать одним нажатием", но и "посмотреть исходный текст в формате Markdown";
|
92 |
+
- Укажите язык ответа, чтобы ChatGPT всегда отвечал на определенном языке.
|
93 |
+
|
94 |
+
### 📜 История чатов
|
95 |
+
- История диалогов будет сохраняться автоматически, не нужно беспокоиться о том, что после вопросов они исчезнут;
|
96 |
+
- История диалогов защищена для каждого пользователя, никто кроме вас не может ее видеть;
|
97 |
+
- Переименуйте историю диалога, чтобы было удобнее искать в будущем;
|
98 |
+
- <sup>New!</sup> Магическое автоматическое именование истории диалога: позволяет LLM понять содержание диалога и автоматически называть историю диалога!
|
99 |
+
- <sup>New!</sup> Поиск истории диалога, поддержка регулярных выражений!
|
100 |
+
|
101 |
+
### 🖼️ Красивый и компактный интерфейс
|
102 |
+
- Собственная тема Small-and-Beautiful принесет вам красивые и компактные впечатления;
|
103 |
+
- Автоматическое переключение светлой и темной темы обеспечит комфорт в любое время суток;
|
104 |
+
- Идеальное отображение LaTeX / таблиц / блоков кода, поддержка подсветки синтаксиса;
|
105 |
+
- <sup>New!</sup> Нелинейная анимация, эффект матового стекла – он такой изысканный, не похожий на Gradio!
|
106 |
+
- <sup>New!</sup> Поддержка Windows / macOS / Linux / iOS / Android, от иконки до адаптации под экраны с вырезами, предоставляет оптимальный опыт!
|
107 |
+
- <sup>New!</sup> Поддержка установки в качестве PWA-приложения, для более нативного опыта!
|
108 |
+
|
109 |
+
### 👨💻 Технические возможности
|
110 |
+
- <sup>New!</sup> Поддержка Fine-tune (тонкой настройки) gpt-3.5!
|
111 |
+
- Множество настраиваемых параметров для LLM;
|
112 |
+
- Поддержка из��енения api-host;
|
113 |
+
- Поддержка настройки настраиваемого прокси-сервера;
|
114 |
+
- Поддержка балансировки нагрузки между несколькими ключами API.
|
115 |
+
|
116 |
+
### ⚒️ Развертывание на сервере
|
117 |
+
- Развертывание на сервере: установите `"server_name": "0.0.0.0", "server_port": <порт>",` в `config.json`.
|
118 |
+
- Получение общедоступной ссылки: установите `"share": true` в `config.json`. Обратите внимание, что программа должна быть запущена, чтобы можно было получить доступ по общедоступной ссылке.
|
119 |
+
- Использование на Hugging Face: рекомендуется скопировать **Space** в правом верхнем углу, а затем использовать его, чтобы приложение было более отзывчивым.
|
120 |
+
|
121 |
+
## Быстрый старт
|
122 |
+
|
123 |
+
```shell
|
124 |
+
git clone https://github.com/GaiZhenbiao/ChuanhuChatGPT.git
|
125 |
+
cd ChuanhuChatGPT
|
126 |
+
pip install -r requirements.txt
|
127 |
+
```
|
128 |
+
|
129 |
+
Затем создайте копию `config_example.json`, переименуйте ее в `config.json`, а затем укажите в файле свой API-ключ и другие настройки.
|
130 |
+
|
131 |
+
```shell
|
132 |
+
python ChuanhuChatbot.py
|
133 |
+
```
|
134 |
+
|
135 |
+
Откроется окно браузера, и вы сможете общаться с ChatGPT.
|
136 |
+
|
137 |
+
> **Примечание**
|
138 |
+
>
|
139 |
+
> Подробные инструкции см. на нашей [wiki-странице](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程).
|
140 |
+
|
141 |
+
## Поиск и устранение неисправностей
|
142 |
+
|
143 |
+
При возникновении проблем следует сначала попробовать вручную подтянуть последние изменения этого проекта. Примерная инструкция:
|
144 |
+
|
145 |
+
1. Загрузите архив с последней версией кода, нажав на кнопку `Download ZIP` на веб-странице, или
|
146 |
+
```shell
|
147 |
+
git pull https://github.com/GaiZhenbiao/ChuanhuChatGPT.git main -f
|
148 |
+
```
|
149 |
+
2. Попробуйте установить зависимости еще раз (так как в этом проекте могли появиться новые зависимости)
|
150 |
+
```
|
151 |
+
pip install -r requirements.txt
|
152 |
+
```
|
153 |
+
|
154 |
+
Как правило, большинство проблем можно решить, выполнив следующие действия.
|
155 |
+
|
156 |
+
Если проблема сохраняется, обратитесь к этой странице: [Часто задаваемые вопросы (FAQ)](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/常见问题)
|
157 |
+
|
158 |
+
На этой странице перечислены практически все возможные проблемы и способы их решения. Пожалуйста, внимательно прочитайте его.
|
159 |
+
|
160 |
+
## Дополнительная информация
|
161 |
+
|
162 |
+
Более подробную информацию можно найти в нашей [wiki](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki):
|
163 |
+
|
164 |
+
- [Как добавить перевод](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/Localization)
|
165 |
+
- [Как внести вклад](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/贡献指南)
|
166 |
+
- [Как цитировать проект](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用许可#如何引用该项目)
|
167 |
+
- [Журнал изменений проекта](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/更新日志)
|
168 |
+
- [Лицензия проекта](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用许可)
|
169 |
+
|
170 |
+
## Starchart
|
171 |
+
|
172 |
+
[![Star History Chart](https://api.star-history.com/svg?repos=GaiZhenbiao/ChuanhuChatGPT&type=Date)](https://star-history.com/#GaiZhenbiao/ChuanhuChatGPT&Date)
|
173 |
+
|
174 |
+
## Помощники
|
175 |
+
|
176 |
+
<a href="https://github.com/GaiZhenbiao/ChuanhuChatGPT/graphs/contributors">
|
177 |
+
<img src="https://contrib.rocks/image?repo=GaiZhenbiao/ChuanhuChatGPT" />
|
178 |
+
</a>
|
179 |
+
|
180 |
+
## Спонсорство
|
181 |
+
|
182 |
+
🐯 Если этот проект будет вам полезен, не стесняйтесь угостить меня колой или чашкой кофе~.
|
183 |
+
|
184 |
+
<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>
|
185 |
+
|
186 |
+
<img width="250" alt="image" src="https://user-images.githubusercontent.com/51039745/226920291-e8ec0b0a-400f-4c20-ac13-dafac0c3aeeb.JPG">
|
requirements.txt
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
-
gradio==3.
|
2 |
-
gradio_client==0.
|
3 |
pypinyin
|
4 |
tiktoken
|
5 |
socksio
|
@@ -7,7 +7,7 @@ tqdm
|
|
7 |
colorama
|
8 |
googlesearch-python
|
9 |
Pygments
|
10 |
-
langchain==0.0.
|
11 |
markdown
|
12 |
PyPDF2
|
13 |
pdfplumber
|
@@ -17,12 +17,17 @@ openpyxl
|
|
17 |
pandoc
|
18 |
wolframalpha
|
19 |
faiss-cpu==1.7.4
|
20 |
-
duckduckgo-search
|
21 |
arxiv
|
22 |
wikipedia
|
23 |
google.generativeai
|
24 |
-
openai
|
25 |
unstructured
|
26 |
google-api-python-client
|
27 |
tabulate
|
28 |
ujson
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
gradio==3.43.2
|
2 |
+
gradio_client==0.5.0
|
3 |
pypinyin
|
4 |
tiktoken
|
5 |
socksio
|
|
|
7 |
colorama
|
8 |
googlesearch-python
|
9 |
Pygments
|
10 |
+
langchain==0.0.316
|
11 |
markdown
|
12 |
PyPDF2
|
13 |
pdfplumber
|
|
|
17 |
pandoc
|
18 |
wolframalpha
|
19 |
faiss-cpu==1.7.4
|
20 |
+
duckduckgo-search>=3.9.5
|
21 |
arxiv
|
22 |
wikipedia
|
23 |
google.generativeai
|
24 |
+
openai==0.28.1
|
25 |
unstructured
|
26 |
google-api-python-client
|
27 |
tabulate
|
28 |
ujson
|
29 |
+
python-docx
|
30 |
+
websocket_client
|
31 |
+
pydantic==1.10.8
|
32 |
+
google-search-results
|
33 |
+
anthropic==0.3.11
|
requirements_advanced.txt
CHANGED
@@ -1,11 +1,12 @@
|
|
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 |
-
|
|
|
|
|
|
|
|
|
|
1 |
transformers
|
2 |
huggingface_hub
|
3 |
torch
|
|
|
|
|
|
|
4 |
cpm-kernels
|
5 |
sentence_transformers
|
6 |
accelerate
|
7 |
sentencepiece
|
8 |
+
llama-cpp-python
|
9 |
+
transformers_stream_generator
|
10 |
+
einops
|
11 |
+
optimum
|
12 |
+
auto-gptq
|
templates/6 Russian Prompts.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
web_assets/.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
web_assets/html/chatbot_header_btn.html
ADDED
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div id="header-btn-groups">
|
2 |
+
<div class="btn-bar-group" style="margin-left: -12px;">
|
3 |
+
<span class="show-on-gpt">
|
4 |
+
<button id="chuanhu-training-btn" onclick="openTrainingBox()" class="chuanhu-ui-btn">
|
5 |
+
<!-- <svg width="24px" height="24px" viewBox="0 0 45.297 28.8394" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
6 |
+
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
7 |
+
<g fill="currentColor" fill-rule="nonzero">
|
8 |
+
<path d="M0,23.4288 C0,27.0248 1.8307,28.8394 5.45907,28.8394 L39.8379,28.8394 C43.4663,28.8394 45.297,27.0248 45.297,23.4288 L45.297,5.41055 C45.297,1.81453 43.4663,0 39.8379,0 L9.91219,0 C6.82641,0 5.13938,1.74422 4.24945,4.43907 L0.618281,15.4643 C0.1875,16.7405 0,17.8041 0,19.4644 L0,23.4288 Z M17.6306,14.2226 L17.6306,8.14923 C17.6306,7.09126 18.2522,6.46969 19.3263,6.46969 L36.3459,6.46969 C37.4201,6.46969 38.0344,7.09126 38.0344,8.14923 L38.0344,14.2226 C38.0344,15.2498 37.4201,15.8714 36.3459,15.8714 L19.3263,15.8714 C18.2522,15.8714 17.6306,15.2498 17.6306,14.2226 Z M6.14415,15.8714 C5.12415,15.8714 4.63102,15.0713 5.01259,13.8724 L7.02539,7.75805 C7.27758,6.97805 7.66875,6.46969 8.95946,6.46969 L11.2486,6.46969 C12.3066,6.46969 12.9443,7.09126 12.9443,8.14923 L12.9443,14.2226 C12.9443,15.2498 12.3066,15.8714 11.2486,15.8714 L6.14415,15.8714 Z" fill-opacity="0.85"></path>
|
9 |
+
</g>
|
10 |
+
</g>
|
11 |
+
</svg> -->
|
12 |
+
<svg width="24px" height="24px" viewBox="0 0 21.4889 22.038" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
13 |
+
<g transform-origin="center" transform="scale(0.85)">
|
14 |
+
<path d="M1.1492 20.81C2.69607 22.3569 4.95779 22.3803 6.51638 20.5991C8.18045 18.7006 10.0672 15.1381 12.6922 12.5131C14.6961 10.5092 17.1101 12.3959 19.8875 9.75923C21.0711 8.63423 21.7039 7.02876 21.4226 5.88032L17.8015 6.87642C17.2976 7.00532 16.8992 6.66548 16.7234 6.05611L16.4539 5.14204C16.2781 4.53267 16.5125 4.04048 17.0164 3.89986L20.6258 2.9272C20.532 2.57564 20.1922 2.09517 19.782 1.67329C17.6258-0.553269 14.0281-0.494675 11.9539 1.47407C8.86013 4.40376 11.1687 7.49751 9.23513 9.43111C6.80935 11.8569 3.24685 13.7788 1.34842 15.4428C-0.432835 17.0014-0.397679 19.2631 1.1492 20.81ZM2.13357 19.8256C1.17263 18.8413 1.17263 17.3881 2.30935 16.4038C4.19607 14.7514 8.00467 12.6303 10.2195 10.4155C12.5867 8.04829 10.0086 5.16548 12.9617 2.45845C14.4617 1.06392 17.1804 1.00532 18.8914 2.59907L19.2429 1.9897L16.7351 2.64595C15.3523 3.00923 14.7429 4.07564 15.1531 5.51704L15.4109 6.40767C15.8797 8.01314 16.8054 8.45845 18.0594 8.11861L20.6609 7.41548L20.0398 7.09907C19.8406 7.75532 19.4773 8.3647 18.9617 8.86861C16.7351 11.0483 14.075 9.17329 11.7078 11.5288C9.30545 13.9194 7.20779 17.7514 5.55545 19.6499C4.54763 20.81 3.09451 20.81 2.13357 19.8256ZM13.0086 9.09126L15.0125 8.5522C15.1883 8.50532 15.2937 8.31782 15.2469 8.11861C15.2 7.94282 15.0242 7.82564 14.825 7.88423L12.8328 8.42329C12.657 8.47017 12.5515 8.65767 12.5867 8.84517C12.6219 9.04439 12.8211 9.13814 13.0086 9.09126ZM12.7625 8.08345L14.7429 7.55611C14.9304 7.50923 15.0359 7.32173 14.989 7.12251C14.9422 6.93501 14.7429 6.82954 14.5672 6.87642L12.575 7.41548C12.3875 7.46236 12.282 7.66157 12.3289 7.82564C12.3875 8.03657 12.5633 8.14204 12.7625 8.08345ZM12.5164 7.07564L14.4969 6.54829C14.6844 6.50142 14.7898 6.31392 14.7429 6.1147C14.6961 5.9272 14.4969 5.82173 14.3211 5.86861L12.3289 6.40767C12.1414 6.45454 12.0359 6.65376 12.0828 6.81782C12.1414 7.02876 12.3172 7.13423 12.5164 7.07564ZM16.5242 10.5444L17.4265 10.3452L16.3133 6.22017L15.4109 6.40767ZM3.80935 19.3217C4.44217 19.3217 4.96951 18.8061 4.96951 18.1616C4.96951 17.5288 4.44217 17.0014 3.80935 17.0014C3.16482 17.0014 2.63748 17.5288 2.63748 18.1616C2.63748 18.8061 3.16482 19.3217 3.80935 19.3217Z" fill="currentColor" fill-opacity="0.85"/>
|
15 |
+
</g>
|
16 |
+
</svg>
|
17 |
+
</button>
|
18 |
+
</span>
|
19 |
+
</div>
|
20 |
+
|
21 |
+
<div class="btn-bar-group">
|
22 |
+
<button id="new-chat-btn" onclick="newChatClick()" class="chuanhu-ui-btn">
|
23 |
+
<!-- <svg width="24px" height="24px" viewBox="0 0 41.3058 37.9805" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
24 |
+
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
25 |
+
<g fill-rule="nonzero">
|
26 |
+
<path d="M7.85906,37.9732 C10.2516,37.9732 15.1013,35.6613 18.7802,33.1193 C31.3151,33.6708 41.3058,26.4138 41.3058,16.6013 C41.3058,7.42008 32.1359,0 20.6529,0 C9.17883,0 0,7.42008 0,16.6013 C0,22.5973 3.85266,27.9152 9.65789,30.6202 C8.82141,32.2172 7.33664,34.2469 6.52195,35.292 C5.57226,36.5116 6.08883,37.9732 7.85906,37.9732 Z M9.48751,35.2875 C9.34688,35.336 9.30727,35.2334 9.40829,35.1089 C10.392,33.8965 11.858,32.0149 12.5182,30.7552 C12.9734,29.9184 12.8473,29.1593 11.8221,28.6863 C6.06376,26.0217 2.68407,21.6335 2.68407,16.6013 C2.68407,8.91657 10.6542,2.66954 20.6529,2.66954 C30.6677,2.66954 38.6217,8.91657 38.6217,16.6013 C38.6217,24.2698 30.6677,30.5241 20.6529,30.5241 C20.1642,30.5241 19.5356,30.495 18.747,30.4659 C18.0687,30.4587 17.5069,30.66 16.9006,31.1402 C14.4764,32.7921 11.1403,34.7288 9.48751,35.2875 Z" fill-opacity="0.85" fill="currentColor"></path>
|
27 |
+
<path d="M12.233,16.7468 C12.233,17.5238 12.7908,18.0816 13.6235,18.0816 L19.2947,18.0816 L19.2947,23.7778 C19.2947,24.5855 19.8525,25.1522 20.6295,25.1522 C21.4371,25.1522 22.0111,24.5927 22.0111,23.7778 L22.0111,18.0816 L27.7146,18.0816 C28.515,18.0816 29.0817,17.5238 29.0817,16.7468 C29.0817,15.9391 28.5223,15.3652 27.7146,15.3652 L22.0111,15.3652 L22.0111,9.67782 C22.0111,8.85399 21.4371,8.28727 20.6295,8.28727 C19.8525,8.28727 19.2947,8.86125 19.2947,9.67782 L19.2947,15.3652 L13.6235,15.3652 C12.7835,15.3652 12.233,15.9391 12.233,16.7468 Z" fill-opacity="0.85" fill="currentColor"></path>
|
28 |
+
</g>
|
29 |
+
</g>
|
30 |
+
</svg> -->
|
31 |
+
<svg width="24px" height="24px" viewBox="0 0 15.0076 15.0274" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
32 |
+
<g transform-origin="center" transform="scale(0.75)">
|
33 |
+
<path d="M0 7.50785C0 7.89996 0.328243 8.23184 0.723986 8.23184L6.78387 8.23184L6.78387 14.2917C6.78387 14.6794 7.11574 15.0157 7.50785 15.0157C7.89996 15.0157 8.22375 14.6794 8.22375 14.2917L8.22375 8.23184L14.2917 8.23184C14.6794 8.23184 15.0076 7.89996 15.0076 7.50785C15.0076 7.11574 14.6794 6.78387 14.2917 6.78387L8.22375 6.78387L8.22375 0.723986C8.22375 0.336329 7.89996 0 7.50785 0C7.11574 0 6.78387 0.336329 6.78387 0.723986L6.78387 6.78387L0.723986 6.78387C0.328243 6.78387 0 7.11574 0 7.50785Z" fill="currentColor" fill-opacity="0.85"/>
|
34 |
+
</g>
|
35 |
+
</svg>
|
36 |
+
</button>
|
37 |
+
|
38 |
+
<div class="nav-item-dropdown">
|
39 |
+
<button id="export-chat-btn" onclick="" class="chuanhu-ui-btn dropdown-trigger">
|
40 |
+
<svg width="24px" height="24px" viewBox="0 0 16.4883 25.0898" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
41 |
+
<g stroke="none" fill="currentColor" fill-rule="nonzero" transform-origin="center" transform="scale(1.1)">
|
42 |
+
<path d="M13.5,7.39453 C15.5039,7.39453 16.4883,8.37891 16.4883,10.3477 L16.4883,19.3594 C16.4883,21.3281 15.5039,22.3125 13.5,22.3125 L2.98828,22.3125 C0.996094,22.3125 0,21.3281 0,19.3594 L0,10.3477 C0,8.37891 0.996094,7.39453 2.98828,7.39453 L5.554,7.394 L5.554,9.093 L3.01172,9.09375 C2.21760235,9.09375 1.74528291,9.49859318 1.69246372,10.2789831 L1.6875,10.4297 L1.6875,19.2773 C1.6875,20.168 2.16797,20.6133 3.01172,20.6133 L13.4766,20.6133 C14.3086,20.6133 14.8008,20.168 14.8008,19.2773 L14.8008,10.4297 C14.8008,9.55078 14.3086,9.09375 13.4766,9.09375 L10.921,9.093 L10.921,7.394 Z" fill-opacity="0.85"></path>
|
43 |
+
<path d="M8.23828,15.0469 C8.69531,15.0469 9.08203,14.6719 9.08203,14.2266 L9.08203,5.08594 L9.01172,3.67969 L9.50391,4.21875 L10.793,5.61328 C10.9453,5.77734 11.1562,5.85938 11.3555,5.85938 C11.8008,5.85938 12.1289,5.55469 12.1289,5.13281 C12.1289,4.89844 12.0352,4.73438 11.8711,4.58203 L8.84766,1.6875 C8.63672,1.47656 8.46094,1.40625 8.23828,1.40625 C8.02734,1.40625 7.85156,1.47656 7.62891,1.6875 L4.60547,4.58203 C4.45312,4.73438 4.35938,4.89844 4.35938,5.13281 C4.35938,5.55469 4.67578,5.85938 5.12109,5.85938 C5.32031,5.85938 5.54297,5.77734 5.69531,5.61328 L6.98438,4.21875 L7.47656,3.67969 L7.40625,5.08594 L7.40625,14.2266 C7.40625,14.6719 7.79297,15.0469 8.23828,15.0469 Z" fill-opacity="0.85"></path>
|
44 |
+
</g>
|
45 |
+
</svg>
|
46 |
+
</button>
|
47 |
+
<div class="dropdown-menu">
|
48 |
+
<div class="dropdown-menu-item">
|
49 |
+
<button onclick="jsonDownloadClick()">{json_label}</button>
|
50 |
+
</div>
|
51 |
+
<div class="dropdown-menu-item">
|
52 |
+
<button onclick="mdDownloadClick()">{md_label}</button>
|
53 |
+
</div>
|
54 |
+
</div>
|
55 |
+
</div>
|
56 |
+
|
57 |
+
<button id="open-toolbox-btn" onclick="toolboxClick()" class="chuanhu-ui-btn">
|
58 |
+
<!-- <svg width="24px" height="24px" viewBox="0 0 33.5163 33.5705" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
59 |
+
<g stroke="none" fill="currentColor" fill-rule="nonzero" transform-origin="center" transform="scale(0.8)">
|
60 |
+
<path d="M5.58422,33.5705 L27.9321,33.5705 C31.6493,33.5705 33.5163,31.6889 33.5163,28.0348 L33.5163,5.57367 C33.5163,1.91953 31.6493,0.0379686 27.9321,0.0379686 L5.58422,0.0379686 C1.8832,0.0379686 0,1.905 0,5.57367 L0,28.0348 C0,31.7034 1.8832,33.5705 5.58422,33.5705 Z M5.6311,30.9495 C3.67477,30.9495 2.60485,29.928 2.60485,27.907 L2.60485,5.70141 C2.60485,3.69657 3.67477,2.65899 5.6311,2.65899 L27.8852,2.65899 C29.8125,2.65899 30.9115,3.69657 30.9115,5.70141 L30.9115,27.907 C30.9115,29.928 29.8125,30.9495 27.8852,30.9495 L5.6311,30.9495 Z" fill-opacity="0.85"></path>
|
61 |
+
<path d="M7.69266,12.7402 L17.3438,12.7402 L17.3438,10.572 L7.69266,10.572 C7.07907,10.572 6.60047,11.0505 6.60047,11.648 C6.60047,12.2616 7.07907,12.7402 7.69266,12.7402 Z M20.021,15.3488 C22.0545,15.3488 23.704,13.683 23.704,11.6334 C23.704,9.6 22.0545,7.9343 20.021,7.9343 C17.9876,7.9343 16.3219,9.6 16.3219,11.6334 C16.3219,13.683 17.9876,15.3488 20.021,15.3488 Z M20.021,13.5841 C18.922,13.5841 18.0865,12.7179 18.0865,11.6262 C18.0865,10.5345 18.922,9.69165 20.021,9.69165 C21.0966,9.69165 21.9483,10.5345 21.9483,11.6262 C21.9483,12.7179 21.0966,13.5841 20.021,13.5841 Z M22.5487,12.7402 L25.8884,12.7402 C26.4534,12.7402 26.932,12.2616 26.932,11.648 C26.932,11.0505 26.4534,10.572 25.8884,10.572 L22.5487,10.572 L22.5487,12.7402 Z M25.8237,20.5158 L16.1726,20.5158 L16.1726,22.6913 L25.8237,22.6913 C26.4534,22.6913 26.932,22.2054 26.932,21.608 C26.932,21.0016 26.4534,20.5158 25.8237,20.5158 Z M13.4953,17.9145 C11.4781,17.9145 9.81962,19.5802 9.81962,21.6225 C9.81962,23.6559 11.4781,25.3216 13.4953,25.3216 C15.5288,25.3216 17.1945,23.6559 17.1945,21.6225 C17.1945,19.5802 15.5288,17.9145 13.4953,17.9145 Z M13.4953,19.6791 C14.5943,19.6791 15.4298,20.538 15.4298,21.6298 C15.4298,22.7288 14.5943,23.5643 13.4953,23.5643 C12.4198,23.5643 11.5842,22.7288 11.5842,21.6298 C11.5842,20.538 12.4198,19.6791 13.4953,19.6791 Z M10.9838,20.5158 L7.64415,20.5158 C7.07907,20.5158 6.60047,21.0016 6.60047,21.608 C6.60047,22.2054 7.07907,22.6913 7.64415,22.6913 L10.9838,22.6913 L10.9838,20.5158 Z" fill-opacity="0.85" transform="translate(16.7662, 16.628) scale(-1, 1) translate(-16.7662, -16.628)"></path>
|
62 |
+
</g>
|
63 |
+
</svg> -->
|
64 |
+
<svg width="24px" height="24px" viewBox="0 0 17.0977 17.0977" viewBox="0 0 17.0742 17.0977" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
65 |
+
<g transform-origin="center" transform="scale(0.82)" fill="currentColor" fill-rule="nonzero" fill-opacity="0.82">
|
66 |
+
<path d="M2.98828,17.0977 L14.0859,17.0977 C16.0898,17.0977 17.0742,16.1133 17.0742,14.1445 L17.0742,2.96484 C17.0742,0.996094 16.0898,0.0117188 14.0859,0.0117188 L2.98828,0.0117188 C0.996094,0.0117188 0,0.996094 0,2.96484 L0,14.1445 C0,16.1133 0.996094,17.0977 2.98828,17.0977 Z M3.01172,15.3984 C2.16797,15.3984 1.6875,14.9531 1.6875,14.0625 L1.6875,3.04688 C1.6875,2.16797 2.16797,1.71094 3.01172,1.71094 L14.0625,1.71094 C14.9062,1.71094 15.3867,2.16797 15.3867,3.04688 L15.3867,14.0625 C15.3867,14.9531 14.9062,15.3984 14.0625,15.3984 L3.01172,15.3984 Z"></path>
|
67 |
+
<path d="M4.34766,6.66797 L8.67188,6.66797 L8.67188,5.29688 L4.34766,5.29688 C3.96094,5.29688 3.65625,5.60156 3.65625,5.97656 C3.65625,6.36328 3.96094,6.66797 4.34766,6.66797 Z M9.89062,7.86328 C10.9219,7.86328 11.7539,7.01953 11.7539,5.97656 C11.7539,4.94531 10.9219,4.10156 9.89062,4.10156 C8.85938,4.10156 8.01562,4.94531 8.01562,5.97656 C8.01562,7.01953 8.85938,7.86328 9.89062,7.86328 Z M9.89062,6.83203 C9.41016,6.83203 9.04688,6.45703 9.04688,5.97656 C9.04688,5.49609 9.41016,5.13281 9.89062,5.13281 C10.3594,5.13281 10.7344,5.49609 10.7344,5.97656 C10.7344,6.45703 10.3594,6.83203 9.89062,6.83203 Z M11.0273,6.66797 L12.7734,6.66797 C13.125,6.66797 13.4297,6.36328 13.4297,5.97656 C13.4297,5.60156 13.125,5.29688 12.7734,5.29688 L11.0273,5.29688 L11.0273,6.66797 Z M12.7266,10.207 L8.40234,10.207 L8.40234,11.5781 L12.7266,11.5781 C13.125,11.5781 13.4297,11.2734 13.4297,10.8984 C13.4297,10.5117 13.125,10.207 12.7266,10.207 Z M7.18359,9.01172 C6.16406,9.01172 5.32031,9.85547 5.32031,10.8984 C5.32031,11.9297 6.16406,12.7734 7.18359,12.7734 C8.21484,12.7734 9.05859,11.9297 9.05859,10.8984 C9.05859,9.85547 8.21484,9.01172 7.18359,9.01172 Z M7.18359,10.043 C7.66406,10.043 8.02734,10.418 8.02734,10.8984 C8.02734,11.3789 7.66406,11.7422 7.18359,11.7422 C6.71484,11.7422 6.35156,11.3789 6.35156,10.8984 C6.35156,10.418 6.71484,10.043 7.18359,10.043 Z M6.05859,10.207 L4.3125,10.207 C3.96094,10.207 3.65625,10.5117 3.65625,10.8984 C3.65625,11.2734 3.96094,11.5781 4.3125,11.5781 L6.05859,11.5781 L6.05859,10.207 Z" transform="translate(8.543, 8.4375) scale(-1, 1) translate(-8.543, -8.4375)"></path>
|
68 |
+
</g>
|
69 |
+
</svg>
|
70 |
+
</button>
|
71 |
+
</div>
|
72 |
+
</div>
|
web_assets/html/chatbot_more.html
ADDED
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div>
|
2 |
+
<div id="chatbot-input-more-area">
|
3 |
+
<span class="chatbot-input-more-label-group">
|
4 |
+
<div class="switch-checkbox">
|
5 |
+
<label>
|
6 |
+
<input type="checkbox" name="single-session-cb" data-testid="checkbox" style="transform: scale(0.8); margin: 0;">
|
7 |
+
<span class="chatbot-input-more-span">{single_turn_label}</span>
|
8 |
+
</label>
|
9 |
+
</div>
|
10 |
+
|
11 |
+
<div class="switch-checkbox">
|
12 |
+
<label>
|
13 |
+
<input type="checkbox" name="online-search-cb" data-testid="checkbox" style="transform: scale(0.8); margin: 0;">
|
14 |
+
<span class="chatbot-input-more-span">{websearch_label}</span>
|
15 |
+
</label>
|
16 |
+
</div>
|
17 |
+
</span>
|
18 |
+
|
19 |
+
<span class="chatbot-input-more-label-group">
|
20 |
+
<div class="chatbot-input-more-btn last-btn">
|
21 |
+
<label class="may-disable-label">
|
22 |
+
<div id="uploaded-files-div">
|
23 |
+
<span class="chatbot-input-more-span tooltip-toggle" aria-label="{uploaded_files_tip}">{uploaded_files_label}</span>
|
24 |
+
<span class="chatbot-input-more-icon" id="uploaded-files-count"></span>
|
25 |
+
</div>
|
26 |
+
<button id="upload-files-btn">
|
27 |
+
<span class="chatbot-input-more-span">{upload_file_label}</span>
|
28 |
+
<span class="chatbot-input-more-icon">
|
29 |
+
<svg width="18px" height="22px" viewBox="0 0 17.6625708 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
30 |
+
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
31 |
+
<g fill="currentColor" fill-rule="nonzero">
|
32 |
+
<path d="M10.6020285,2.51882667 C11.4362625,2.51882667 11.8921676,2.64807396 12.4438001,3.21682942 L16.9677143,7.80362991 C17.5473088,8.39718377 17.6625708,8.80801259 17.6625708,9.74013504 L17.6625708,17.0701838 C17.6625708,18.6697194 16.8588053,19.4835978 15.2701606,19.4835978 L9.30367012,19.4838726 C9.50801444,19.132339 9.67081559,18.754537 9.78494219,18.3575337 L15.2149282,18.3578162 C16.0814028,18.3578162 16.5329428,17.8954285 16.5329428,17.0499579 L16.5329428,9.75491554 L11.9107944,9.75491554 C10.9798389,9.75491554 10.4963609,9.29343541 10.4963609,8.34048196 L10.4963609,3.64458667 L6.87556994,3.64458667 C6.00213732,3.64458667 5.55375219,4.12267974 5.55375219,4.95246234 L5.55332282,12.0499339 C5.36755588,12.0285691 5.17882362,12.0175857 4.9877281,12.0175857 C4.79846417,12.0175857 4.61149369,12.028399 4.42740668,12.0494356 L4.42797059,4.93219317 C4.42797059,3.3327051 5.23415624,2.51882667 6.81337946,2.51882667 Z M11.552216,3.86783276 L11.552216,8.21151991 C11.552216,8.55164434 11.6926308,8.69205911 12.0359101,8.69205911 L16.3097226,8.69205911 L11.552216,3.86783276 Z" fill-opacity="0.85"></path>
|
33 |
+
<path d="M4.9877281,13.0174305 C7.17286548,13.0174305 8.97241326,14.8169783 8.97241326,17.0052706 C8.97241326,19.1904512 7.15190483,20.9970003 4.9877281,20.9970003 C2.80254317,20.9970003 0.999853452,19.1974525 0.999853452,17.0052706 C0.999853452,14.82009 2.80254317,13.0174305 4.9877281,13.0174305 Z M4.99784107,14.437007 C4.88115289,14.437007 4.7753124,14.4852382 4.64150995,14.6120393 L2.60482154,16.530609 C2.48641329,16.6350666 2.4357663,16.7447535 2.42877798,16.8911323 C2.414797,17.1440431 2.62022006,17.325342 2.87314384,17.325342 C3.00310422,17.3323433 3.12991834,17.2638862 3.21236934,17.1782716 L3.90166369,16.4757224 L4.5558954,15.8144894 L4.51466558,16.8528413 L4.51466558,19.0792085 C4.51466558,19.332854 4.73408257,19.5421148 4.99784107,19.5421148 C5.25844467,19.5421148 5.47470676,19.332854 5.47470676,19.0792085 L5.47470676,16.8528413 L5.44363313,15.8144894 L6.08075058,16.4757224 L6.78018815,17.1782716 C6.86960587,17.2638862 6.98560256,17.3183839 7.11555862,17.325342 C7.36531454,17.3393445 7.56061597,17.1440431 7.56061597,16.8911323 C7.56061597,16.7479084 7.50996466,16.6350666 7.39159099,16.530609 L5.34090431,14.6120393 C5.22352465,14.498506 5.12779713,14.437007 4.99784107,14.437007 Z" fill-opacity="0.85"></path>
|
34 |
+
</g>
|
35 |
+
</g>
|
36 |
+
</svg>
|
37 |
+
</span>
|
38 |
+
</button>
|
39 |
+
</label>
|
40 |
+
</div>
|
41 |
+
</span>
|
42 |
+
</div>
|
43 |
+
|
44 |
+
<!-- get more button -->
|
45 |
+
<div id="chatbot-input-more-btn-div">
|
46 |
+
<button class="chatbot-input-more-btn" onclick="chatMoreBtnClick()">
|
47 |
+
<!-- <svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
48 |
+
xmlns:xlink="http://www.w3.org/1999/xlink">
|
49 |
+
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
50 |
+
<g fill="currentColor" fill-rule="nonzero">
|
51 |
+
<path
|
52 |
+
d="M15.9930223,31.97976 C24.7467023,31.97976 32,24.7418401 32,15.98988 C32,7.23796297 24.7327468,0 15.9790668,0 C7.23313125,0 0,7.23796297 0,15.98988 C0,24.7418401 7.24706085,31.97976 15.9930223,31.97976 Z"
|
53 |
+
fill-opacity="0.1" class="sm-round-bg"></path>
|
54 |
+
<path
|
55 |
+
d="M8.41162523,16.0038327 C8.41162523,15.2803594 8.92769229,14.7720332 9.65130778,14.7720332 L14.7951802,14.7720332 L14.7951802,9.62925761 C14.7951802,8.91198549 15.2756953,8.40371964 15.9728644,8.40371964 C16.6964799,8.40371964 17.2048198,8.90578429 17.2048198,9.62925761 L17.2048198,14.7720332 L22.3626477,14.7720332 C23.0723077,14.7720332 23.5884006,15.2803594 23.5884006,16.0038327 C23.5884006,16.7008648 23.0660191,17.1952382 22.3626477,17.1952382 L17.2048198,17.1952382 L17.2048198,22.3380138 C17.2048198,23.0614872 16.6964799,23.563526 15.9728644,23.563526 C15.2756953,23.563526 14.7951802,23.0413333 14.7951802,22.3380138 L14.7951802,17.1952382 L9.65130778,17.1952382 C8.93398085,17.1952382 8.41162523,16.7008648 8.41162523,16.0038327 Z"
|
56 |
+
fill-opacity="0.85"></path>
|
57 |
+
</g>
|
58 |
+
</g>
|
59 |
+
</svg> -->
|
60 |
+
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
61 |
+
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
62 |
+
<g fill="currentColor" fill-rule="nonzero">
|
63 |
+
<path d="M15.9930223,31.97976 C24.7467023,31.97976 32,24.7418401 32,15.98988 C32,7.23796297 24.7327468,0 15.9790668,0 C7.23313125,0 0,7.23796297 0,15.98988 C0,24.7418401 7.24706085,31.97976 15.9930223,31.97976 Z" fill-opacity="0.1" class="sm-round-bg"></path>
|
64 |
+
<path d="M23.5318035,18.2475474 C22.2777951,18.2475474 21.2612876,17.2374408 21.2612876,15.9773915 C21.2612876,14.7173421 22.2777951,13.7072355 23.5318035,13.7072355 C24.7781451,13.7072355 25.8086942,14.7173421 25.8086942,15.9773915 C25.8086942,17.2374408 24.7781451,18.2475474 23.5318035,18.2475474 Z" fill-opacity="0.75"></path>
|
65 |
+
<path d="M15.9930223,18.2475474 C14.7327253,18.2475474 13.7224202,17.2374408 13.7224202,15.9773915 C13.7224202,14.7173421 14.7327253,13.7072355 15.9930223,13.7072355 C17.2533193,13.7072355 18.2775798,14.7173421 18.2775798,15.9773915 C18.2775798,17.2374408 17.2533193,18.2475474 15.9930223,18.2475474 Z" fill-opacity="0.75"></path>
|
66 |
+
<path d="M8.468162,18.2475474 C7.22182045,18.2475474 6.19131446,17.2374408 6.19131446,15.9773915 C6.19131446,14.7173421 7.22182045,13.7072355 8.468162,13.7072355 C9.70824943,13.7072355 10.7387124,14.7173421 10.7387124,15.9773915 C10.7387124,17.2374408 9.72220487,18.2475474 8.468162,18.2475474 Z" fill-opacity="0.75"></path>
|
67 |
+
</g>
|
68 |
+
</g>
|
69 |
+
</svg>
|
70 |
+
</button>
|
71 |
+
</div>
|
72 |
+
</div>
|
web_assets/html/close_btn.html
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<button onclick='closeBtnClick("{obj}")'>
|
2 |
+
<svg class="icon-need-hover" stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round"
|
3 |
+
stroke-linejoin="round" height="20" width="20" xmlns="http://www.w3.org/2000/svg"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line>
|
4 |
+
</svg>
|
5 |
+
</button>
|
web_assets/html/func_nav.html
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div id="menu-footer-btn-bar" class="is-gpt">
|
2 |
+
<div class="btn-bar-group">
|
3 |
+
<button id="chuanhu-setting-btn" onclick="openSettingBox()" class="chuanhu-ui-btn">
|
4 |
+
<!-- <svg width="24px" height="24px" viewBox="0 0 39.6797 39.6328" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
5 |
+
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
6 |
+
<g id="gearshape" fill-rule="nonzero">
|
7 |
+
<path d="M17.9766,39.6094 L21.6797,39.6094 C23.1797,39.6094 24.3516,38.6953 24.7031,37.2891 L25.4766,33.9141 L25.8984,33.7734 L28.8047,35.5781 C30.0703,36.3516 31.5469,36.1641 32.6016,35.0859 L35.1797,32.5312 C36.2344,31.4766 36.4453,29.9766 35.6484,28.7578 L33.8203,25.8281 L33.9609,25.4766 L37.3359,24.7031 C38.7422,24.3516 39.6797,23.1562 39.6797,21.6797 L39.6797,18.0703 C39.6797,16.5938 38.7656,15.3984 37.3359,15.0469 L34.0078,14.2266 L33.8438,13.8516 L35.6719,10.9219 C36.4688,9.67969 36.2578,8.22656 35.2031,7.125 L32.625,4.57031 C31.5938,3.51562 30.1172,3.32812 28.8516,4.07812 L25.9219,5.85938 L25.4766,5.69531 L24.7031,2.32031 C24.3516,0.914062 23.1797,0 21.6797,0 L17.9766,0 C16.4766,0 15.3281,0.914062 14.9766,2.32031 L14.2031,5.69531 L13.7344,5.85938 L10.8047,4.07812 C9.5625,3.32812 8.08594,3.51562 7.03125,4.57031 L4.47656,7.125 C3.42188,8.22656 3.21094,9.67969 4.00781,10.9219 L5.8125,13.8516 L5.64844,14.2266 L2.32031,15.0469 C0.914062,15.3984 0,16.5938 0,18.0703 L0,21.6797 C0,23.1562 0.9375,24.3516 2.32031,24.7031 L5.69531,25.4766 L5.83594,25.8281 L4.03125,28.7578 C3.23438,29.9766 3.44531,31.4766 4.5,32.5312 L7.05469,35.0859 C8.10938,36.1641 9.60938,36.3516 10.8516,35.5781 L13.7812,33.7734 L14.2031,33.9141 L14.9766,37.2891 C15.3281,38.6953 16.4766,39.6094 17.9766,39.6094 Z M18.3047,36.3516 C18.0703,36.3516 17.9531,36.25781 17.9297,36.0469 L16.7812,31.4531 C15.5859,31.1484 14.5078,30.7031 13.6875,30.1406 L9.63281,32.6484 C9.46875,32.7422 9.30469,32.7188 9.14062,32.5781 L7.03125,30.4453 C6.86719,30.3047 6.86719,30.1406 6.98438,29.9531 L9.44531,25.9219 C9,25.125 8.48438,24.0469 8.17969,22.8516 L3.5625,21.7266 C3.35156,21.7031 3.25781,21.5859 3.25781,21.3516 L3.25781,18.3516 C3.25781,18.0938 3.32812,18.0234 3.5625,17.9531 L8.15625,16.8516 C8.46094,15.5625 9.07031,14.4375 9.39844,13.7344 L6.96094,9.72656 C6.82031,9.51562 6.82031,9.35156 6.98438,9.1875 L9.11719,7.10156 C9.28125,6.96094 9.39844,6.91406 9.63281,7.03125 L13.6406,9.46875 C14.4609,8.97656 15.6328,8.48438 16.8047,8.15625 L17.9297,3.5625 C17.9531,3.35156 18.0703,3.25781 18.3047,3.25781 L21.375,3.25781 C21.6094,3.25781 21.7266,3.35156 21.75,3.5625 L22.875,8.20312 C24.0938,8.50781 25.1484,9 25.9922,9.49219 L30.0469,7.03125 C30.25781,6.91406 30.375,6.96094 30.5625,7.10156 L32.6953,9.1875 C32.8359,9.35156 32.8594,9.51562 32.7188,9.72656 L30.25781,13.7344 C30.6094,14.4375 31.1953,15.5625 31.5,16.8516 L36.1172,17.9531 C36.3516,18.0234 36.3984,18.0938 36.3984,18.3516 L36.3984,21.3516 C36.3984,21.5859 36.3281,21.7031 36.1172,21.7266 L31.4766,22.8516 C31.1953,24.0469 30.6797,25.125 30.2109,25.9219 L32.6953,29.9531 C32.8125,30.1406 32.8125,30.3047 32.6484,30.4453 L30.5391,32.5781 C30.3516,32.7188 30.1875,32.7422 30.0469,32.6484 L25.9688,30.1406 C25.1719,30.7031 24.0703,31.1484 22.875,31.4531 L21.75,36.0469 C21.7266,36.25781 21.6094,36.3516 21.375,36.3516 L18.3047,36.3516 Z M19.8281,26.8125 C23.6719,26.8125 26.8359,23.6719 26.8359,19.8047 C26.8359,15.9844 23.6719,12.8438 19.8281,12.8438 C15.9844,12.8438 12.8203,15.9844 12.8203,19.8047 C12.8203,23.6484 15.9844,26.8125 19.8281,26.8125 Z M19.8281,23.5781 C17.7656,23.5781 16.1016,21.8906 16.1016,19.8047 C16.1016,17.7656 17.7656,16.0781 19.8281,16.0781 C21.8438,16.0781 23.5312,17.7656 23.5312,19.8047 C23.5312,21.8672 21.8438,23.5781 19.8281,23.5781 Z" id="形状" fill-opacity="0.85" fill="currentColor"></path>
|
8 |
+
</g>
|
9 |
+
</g>
|
10 |
+
</svg> -->
|
11 |
+
<svg width="24px" height="24px" viewBox="0 0 41.5547 40.9700126" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
12 |
+
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" fill-opacity="0.85">
|
13 |
+
<g fill="currentColor" fill-rule="nonzero">
|
14 |
+
<path d="M20.7891,38.3561 C21.2344,38.3561 21.6328,38.3092 22.125,38.2858 L23.2031,40.3483 C23.4375,40.7936 23.8828,41.028 24.375,40.9577 C24.8438,40.8639 25.2188,40.4655 25.2891,39.9733 L25.6172,37.6764 C26.4609,37.442 27.3047,37.1139 28.1484,36.7858 L29.8359,38.3092 C30.2109,38.6608 30.7031,38.7311 31.1719,38.4733 C31.5938,38.2155 31.7812,37.7467 31.6875,37.2545 L31.1953,34.9811 C31.8984,34.4655 32.625,33.903 33.2578,33.2702 L35.3906,34.1608 C35.8594,34.3717 36.3516,34.2311 36.7031,33.8092 C37.0078,33.4577 37.0312,32.942 36.7734,32.5202 L35.5547,30.5514 C36.0703,29.8249 36.4688,29.0514 36.8672,28.2077 L39.1875,28.3249 C39.6797,28.3483 40.125,28.0436 40.2891,27.5983 C40.4531,27.1295 40.2891,26.6139 39.9141,26.3327 L38.0859,24.8795 C38.3203,24.0358 38.5078,23.1686 38.5781,22.2311 L40.7578,21.528 C41.25,21.3639 41.5547,20.9889 41.5547,20.4733 C41.5547,19.9577 41.25,19.5827 40.7578,19.4186 L38.5781,18.7155 C38.5078,17.778 38.3203,16.9342 38.0859,16.067 L39.9141,14.6139 C40.2891,14.3327 40.4531,13.8405 40.2891,13.3717 C40.125,12.9264 39.6797,12.6217 39.1875,12.6452 L36.8672,12.7389 C36.4688,11.8952 36.0703,11.1452 35.5547,10.3952 L36.7734,8.42641998 C37.0312,8.02797998 37.0078,7.51235998 36.7031,7.16078998 C36.3516,6.73891998 35.8594,6.62172998 35.3906,6.80922998 L33.2578,7.67641998 C32.625,7.06703998 31.8984,6.48110998 31.1953,5.96547998 L31.6875,3.71547998 C31.7812,3.19985998 31.5938,2.73110998 31.1719,2.49672998 C30.7031,2.23891998 30.2109,2.28578998 29.8359,2.66078998 L28.1484,4.16078998 C27.3047,3.80922998 26.4609,3.52797998 25.6172,3.27016998 L25.2891,0.996730977 C25.2188,0.504542977 24.8438,0.106105977 24.375,0.0123557768 C23.8828,-0.0579567232 23.4141,0.176417977 23.2031,0.598292977 L22.125,2.66078998 C21.6328,2.63735998 21.2344,2.61391998 20.7891,2.61391998 C20.2969,2.61391998 19.8984,2.63735998 19.4297,2.66078998 L18.3281,0.598292977 C18.1172,0.176417977 17.6719,-0.0579567232 17.1562,0.0123557768 C16.6875,0.106105977 16.3359,0.504542977 16.2656,0.996730977 L15.9375,3.27016998 C15.0703,3.52797998 14.2266,3.80922998 13.4062,4.16078998 L11.6953,2.66078998 C11.3203,2.28578998 10.8281,2.23891998 10.3594,2.49672998 C9.96094,2.73110998 9.75,3.19985998 9.86719,3.71547998 L10.3359,5.96547998 C9.63281,6.48110998 8.90625,7.06703998 8.27344,7.67641998 L6.16406,6.80922998 C5.67188,6.62172998 5.20312,6.73891998 4.85156,7.16078998 C4.54688,7.51235998 4.5,8.02797998 4.75781,8.42641998 L5.97656,10.3952 C5.48438,11.1452 5.0625,11.8952 4.66406,12.7389 L2.34375,12.6452 C1.85156,12.6217 1.40625,12.9264 1.24219,13.3717 C1.10156,13.8405 1.24219,14.3092 1.64062,14.6139 L3.44531,16.067 C3.23438,16.9342 3.04688,17.778 2.97656,18.7155 L0.773438,19.4186 C0.304688,19.5827 0,19.9577 0,20.4733 C0,20.9889 0.304688,21.3639 0.773438,21.528 L2.97656,22.2311 C3.04688,23.1686 3.23438,24.0358 3.44531,24.8795 L1.64062,26.3327 C1.24219,26.6139 1.10156,27.1295 1.24219,27.5983 C1.40625,28.0436 1.85156,28.3483 2.34375,28.3249 L4.66406,28.2077 C5.0625,29.0514 5.48438,29.8249 5.97656,30.5514 L4.75781,32.5202 C4.5,32.942 4.54688,33.4577 4.85156,33.8092 C5.20312,34.2311 5.67188,34.3717 6.16406,34.1608 L8.27344,33.2702 C8.90625,33.903 9.63281,34.4655 10.3359,34.9811 L9.86719,37.2545 C9.77344,37.7467 9.96094,38.2155 10.3594,38.4733 C10.8281,38.7311 11.3203,38.6608 11.6953,38.3092 L13.4062,36.7858 C14.2266,37.1139 15.0703,37.442 15.9375,37.6764 L16.2656,39.9733 C16.3359,40.4655 16.6875,40.8639 17.1562,40.9577 C17.6719,41.028 18.0938,40.7936 18.3281,40.3483 L19.4297,38.2858 C19.8984,38.3092 20.2969,38.3561 20.7891,38.3561 Z M20.7891,35.1686 C12.5859,35.1686 6.25781,28.6295 6.25781,20.4967 C6.25781,12.3405 12.5859,5.80141998 20.7891,5.80141998 C28.9688,5.80141998 35.2969,12.3405 35.2969,20.4967 C35.2969,28.6295 28.9688,35.1686 20.7891,35.1686 Z M17.3672,17.4733 L19.6641,15.9967 L13.5938,5.66078998 L11.2266,7.02016998 L17.3672,17.4733 Z M25.1484,21.8327 L37.2188,21.8327 L37.1953,19.1608 L25.1484,19.1608 L25.1484,21.8327 Z M19.6406,25.0202 L17.3438,23.5202 L10.9922,33.8795 L13.3359,35.2858 L19.6406,25.0202 Z M20.7188,25.5124 C23.4844,25.5124 25.6875,23.2858 25.6875,20.5202 C25.6875,17.7545 23.4844,15.528 20.7188,15.528 C17.9531,15.528 15.7266,17.7545 15.7266,20.5202 C15.7266,23.2858 17.9531,25.5124 20.7188,25.5124 Z M20.7188,22.5592 C19.5703,22.5592 18.6562,21.6686 18.6562,20.5202 C18.6562,19.3717 19.5703,18.4811 20.7188,18.4811 C21.8672,18.4811 22.7578,19.3717 22.7578,20.5202 C22.7578,21.6686 21.8672,22.5592 20.7188,22.5592 Z"></path>
|
15 |
+
</g>
|
16 |
+
</g>
|
17 |
+
</svg>
|
18 |
+
</button>
|
19 |
+
<button id="chuanhu-manual-check-btn" onclick="manualCheckUpdate()" class="chuanhu-ui-btn">
|
20 |
+
<span class="show-on-latest">
|
21 |
+
<svg width="24px" height="24px" viewBox="0 0 45.2923004 37.8516" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
22 |
+
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
23 |
+
<g fill-rule="nonzero">
|
24 |
+
<path d="M0.415684357,19.0078 C-0.381190643,20.1094 -0.0296279434,21.1172 1.44693036,21.1172 L3.86100036,21.1172 C4.96256036,30.4453 13.0719004,37.8281 22.6344004,37.8281 C28.2360004,37.8281 33.2985004,35.3203 36.7672004,31.3828 C37.5641004,30.4922 37.4469004,29.3438 36.6266004,28.7578 C35.8063004,28.1719 34.8219004,28.3828 34.1188004,29.1562 C31.3297004,32.2969 27.2282004,34.2656 22.6344004,34.2656 C14.8532004,34.2656 8.52506036,28.5703 7.47037036,21.1172 L9.97818036,21.1172 C11.4313004,21.1172 11.8063004,20.1094 11.0329004,19.0312 L6.86100036,13.0781 C6.22818036,12.1641 5.24381036,12.1406 4.58756036,13.0781 L0.415684357,19.0078 Z M8.52506036,6.42188 C7.72818036,7.3125 7.84537036,8.4375 8.66568036,9.02344 C9.50943036,9.60938 10.4938004,9.44531 11.1969004,8.64844 C14.0094004,5.53125 18.0876004,3.5625 22.6344004,3.5625 C30.4157004,3.5625 36.7672004,9.25781 37.7985004,16.7109 L35.2907004,16.7109 C33.8376004,16.7109 33.4860004,17.7188 34.2594004,18.8203 L38.4313004,24.75 C39.0641004,25.6641 40.0485004,25.6875 40.7047004,24.75 L44.8766004,18.8438 C45.6735004,17.7188 45.3219004,16.7109 43.8454004,16.7109 L41.4313004,16.7109 C40.3297004,7.38281 32.2204004,0 22.6344004,0 C17.0797004,0 12.0172004,2.48438 8.52506036,6.42188 Z" fill-opacity="0.85" fill="currentColor"></path>
|
25 |
+
</g>
|
26 |
+
</g>
|
27 |
+
</svg>
|
28 |
+
</span>
|
29 |
+
<span class="show-on-outdated">
|
30 |
+
<svg width="24px" height="24px" viewBox="0 0 45.2924004 37.8516" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
31 |
+
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
32 |
+
<g fill="currentColor" fill-rule="nonzero">
|
33 |
+
<path d="M0.415682396,19.0078 C-0.381189604,20.1094 -0.0296276044,21.1172 1.4469304,21.1172 L3.8610104,21.1172 C4.9625604,30.4453 13.0719004,37.8281 22.6344004,37.8281 C28.2360004,37.8281 33.2985004,35.3203 36.7673004,31.3828 C37.5641004,30.4922 37.4469004,29.3437 36.6266004,28.7578 C35.8063004,28.1719 34.8219004,28.3828 34.1188004,29.1563 C31.3297004,32.2969 27.2282004,34.2656 22.6344004,34.2656 C14.8532004,34.2656 8.5250704,28.5703 7.4703704,21.1172 L9.9781804,21.1172 C11.4313004,21.1172 11.8063004,20.1094 11.0329004,19.0312 L6.8610104,13.0781 C6.2281804,12.1641 5.2437904,12.1406 4.5875404,13.0781 L0.415682396,19.0078 Z M8.5250704,6.42187 C7.7281804,7.31251 7.8453904,8.43749 8.6656604,9.02342 C9.5094604,9.60936 10.4938004,9.4453 11.1969004,8.64845 C14.0095004,5.53123 18.0875004,3.56251 22.6344004,3.56251 C30.4157004,3.56251 36.7673004,9.25781 37.7985004,16.7109 L35.2907004,16.7109 C33.8376004,16.7109 33.4860004,17.7188 34.2595004,18.8203 L38.4313004,24.75 C39.0641004,25.6641 40.0485004,25.6875 40.7048004,24.75 L44.8767004,18.8437 C45.6735004,17.7188 45.3222004,16.7109 43.8454004,16.7109 L41.4313004,16.7109 C40.3297004,7.38283 32.2204004,0 22.6344004,0 C17.0797004,0 12.0173004,2.48438 8.5250704,6.42187 Z" fill-opacity="0.85"></path>
|
34 |
+
<path d="M22.6344004,22.2422 C23.6422004,22.2422 24.2048004,21.6797 24.2282004,20.625 L24.5095004,11.0156 C24.5329004,9.96096 23.7126004,9.18749 22.6110004,9.18749 C21.5095004,9.18749 20.7126004,9.93749 20.7360004,10.9922 L21.0173004,20.625 C21.0407004,21.6797 21.6032004,22.2422 22.6344004,22.2422 Z M22.6344004,28.3828 C23.7829004,28.3828 24.7907004,27.4688 24.7907004,26.3203 C24.7907004,25.1484 23.8063004,24.2578 22.6344004,24.2578 C21.4626004,24.2578 20.5016004,25.1719 20.5016004,26.3203 C20.5016004,27.4453 21.4860004,28.3828 22.6344004,28.3828 Z" fill-opacity="0.85"></path>
|
35 |
+
</g>
|
36 |
+
</g>
|
37 |
+
</svg>
|
38 |
+
</span>
|
39 |
+
</button>
|
40 |
+
<!--
|
41 |
+
<button id="chuanhu-training-btn" onclick="openTrainingBox()" class="chuanhu-ui-btn">
|
42 |
+
<svg width="24px" height="24px" viewBox="0 0 37.3359 44.6953" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
43 |
+
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
44 |
+
<g id="brain.filled.head.profile" fill-rule="nonzero">
|
45 |
+
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="37.3359" height="44.6953"></rect>
|
46 |
+
<path d="M21.5156,44.5312 C28.5,44.5312 32.7656,42.0469 32.7656,37.7109 L32.7656,28.7812 C35.6484,26.2031 37.3359,22.1016 37.3359,17.625 C37.3359,7.05469 30.4453,0 20.2031,0 C9.98438,0 3.14062,6.91406 3.14062,17.2266 C3.14062,17.7891 3.16406,18.2578 3.21094,18.7031 L0.960938,22.7109 C0.328125,23.8594 0,25.0078 0,26.0391 C0,27.9844 1.17188,29.5781 3.14062,30.1641 L3.14062,33.6562 C3.14062,37.1719 5.67188,38.8828 8.8125,38.5312 L12.8438,38.1328 L10.4531,35.5781 L10.4531,37.7109 C10.4531,42.0234 14.625,44.5312 21.5156,44.5312 Z M21.5156,41.1562 C16.5703,41.1562 13.6406,39.6328 13.6406,37.125 L13.6406,34.9453 C13.6406,34.7109 13.5234,34.5938 13.3125,34.6172 L8.34375,35.1797 C7.17188,35.2969 6.51562,34.8281 6.51562,33.4453 L6.51562,27.6562 C6.51562,27.4922 6.39844,27.375 6.16406,27.375 L5.13281,27.375 C4.03125,27.375 3.39844,26.8359 3.39844,25.9922 C3.39844,25.5234 3.5625,24.9844 3.89062,24.3984 L6.70312,19.3828 C6.58594,18.6562 6.51562,17.9062 6.51562,17.1797 C6.51562,8.90625 11.9766,3.39844 20.2031,3.39844 C28.4297,3.39844 33.9609,9.07031 33.9609,17.625 C33.9609,21.7266 32.2266,25.3359 29.3672,27.1172 L29.3672,37.125 C29.3672,39.6328 26.4375,41.1562 21.5156,41.1562 Z" id="形状" fill-opacity="0.85" fill="currentColor"></path>
|
47 |
+
<path d="M14.1797,19.7812 C16.2656,19.7812 17.7188,18.375 17.7188,16.4062 C17.7188,15.7031 17.5312,15.1875 17.2031,14.8359 C16.8516,14.5078 16.7109,14.1562 16.7109,13.9219 C16.7109,13.4062 17.1562,13.0312 17.6719,13.0312 C17.8828,13.0312 18.1641,13.0781 18.375,13.2891 C18.4219,13.3359 18.4688,13.4062 18.4922,13.4531 C19.9219,13.2891 20.6484,12.4688 20.6484,11.1328 C20.6484,10.6172 21.0703,10.1719 21.5859,10.1719 C22.1016,10.1719 22.5469,10.6406 22.5469,11.1328 C22.5703,13.2656 21.4922,14.6016 19.4297,15.0703 C19.5703,15.4922 19.6172,15.9609 19.6172,16.4297 C19.6172,18.2109 18.75,19.6641 17.3203,20.4844 C18.1172,20.8594 19.0312,21.0469 20.0156,21.0469 C20.4844,21.0469 20.9766,21 21.4688,20.9062 C21.375,20.6719 21.3516,20.4141 21.3516,20.2031 C21.3516,15.4453 28.1719,14.6484 28.1719,10.4531 C28.1719,8.34375 26.5781,6.72656 24.5859,6.72656 C23.8125,6.72656 23.6719,6.75 23.5078,6.77344 C22.7344,5.95312 21.6328,5.48438 20.6953,5.48438 C18.9844,5.48438 17.8125,6.5625 17.8125,8.15625 C17.8125,8.71875 17.4141,9.09375 16.8516,9.09375 C16.2891,9.09375 15.8906,8.67188 15.9141,8.10938 C15.9141,7.35938 16.1484,6.89062 16.2891,6.44531 C16.0078,6.39844 15.7266,6.375 15.4688,6.375 C13.2656,6.375 11.5547,7.73438 11.5547,9.39844 C11.5547,10.4766 12.2812,11.3438 13.2422,11.3438 C13.7812,11.3438 14.2031,11.7656 14.2031,12.2578 C14.2031,12.7969 13.7578,13.2422 13.2422,13.2422 C11.7656,13.2422 10.6172,12.5625 10.0547,11.4844 C9.51562,12.3516 9.21094,13.3594 9.21094,14.3906 C9.21094,17.4141 11.1562,19.7812 14.1797,19.7812 Z M27.7969,24.5156 C29.7656,24.5156 31.1953,22.3125 31.1953,19.3359 C31.1953,19.125 31.1953,18.8906 31.1953,18.6328 C30.4688,18.9609 29.6016,19.1016 28.6172,19.0312 C28.1016,18.9609 27.7031,18.5625 27.7031,18.0469 C27.7031,17.5312 28.1484,17.0625 28.6641,17.1094 C30.5859,17.2734 31.8516,16.2188 31.8516,14.5078 C31.8516,12.9375 31.125,11.625 29.8828,10.8047 C29.3203,15.9141 23.0156,16.5938 23.0156,20.1328 C23.0156,21.0938 23.6484,21.7734 24.75,21.7734 L25.0078,21.7734 C25.3125,23.3906 26.4375,24.5156 27.7969,24.5156 Z" id="形状" fill-opacity="0.85" fill="currentColor"></path>
|
48 |
+
</g>
|
49 |
+
</g>
|
50 |
+
</svg>
|
51 |
+
</button>
|
52 |
+
-->
|
53 |
+
</div>
|
54 |
+
<div class="btn-bar-group">
|
55 |
+
<button id="chuanhu-appearance-switcher" onclick="btnToggleDarkMode()" class="chuanhu-ui-btn">
|
56 |
+
<span class="show-on-dark">
|
57 |
+
<svg width="24px" height="24px" viewBox="0 0 39.9141 40.0547" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
58 |
+
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
59 |
+
<g fill-rule="nonzero">
|
60 |
+
<path d="M19.9688,7.42969 C20.9531,7.42969 21.7734,6.58594 21.7734,5.60156 L21.7734,1.80469 C21.7734,0.820312 20.9531,0 19.9688,0 C18.9609,0 18.1406,0.820312 18.1406,1.80469 L18.1406,5.60156 C18.1406,6.58594 18.9609,7.42969 19.9688,7.42969 Z M28.8281,11.1328 C29.5312,11.8359 30.7031,11.8594 31.4297,11.1328 L34.125,8.46094 C34.8047,7.75781 34.8047,6.5625 34.125,5.85938 C33.4219,5.15625 32.25,5.15625 31.5469,5.85938 L28.8281,8.57812 C28.1484,9.28125 28.1484,10.4297 28.8281,11.1328 Z M32.5078,20.0156 C32.5078,21 33.3516,21.8438 34.3359,21.8438 L38.0859,21.8438 C39.0938,21.8438 39.9141,21 39.9141,20.0156 C39.9141,19.0312 39.0938,18.1875 38.0859,18.1875 L34.3359,18.1875 C33.3516,18.1875 32.5078,19.0312 32.5078,20.0156 Z M28.8281,28.9219 C28.1484,29.625 28.1484,30.7734 28.8281,31.4766 L31.5469,34.1953 C32.25,34.8984 33.4219,34.875 34.125,34.1719 C34.8047,33.4688 34.8047,32.2969 34.125,31.5938 L31.4062,28.9219 C30.7031,28.2188 29.5312,28.2188 28.8281,28.9219 Z M19.9688,32.6016 C18.9609,32.6016 18.1406,33.4453 18.1406,34.4297 L18.1406,38.2266 C18.1406,39.2109 18.9609,40.0312 19.9688,40.0312 C20.9531,40.0312 21.7734,39.2109 21.7734,38.2266 L21.7734,34.4297 C21.7734,33.4453 20.9531,32.6016 19.9688,32.6016 Z M11.0859,28.9219 C10.3828,28.2188 9.1875,28.2188 8.48438,28.9219 L5.8125,31.5703 C5.10938,32.2734 5.10938,33.4453 5.78906,34.1484 C6.49219,34.8516 7.66406,34.875 8.36719,34.1719 L11.0625,31.4766 C11.7656,30.7734 11.7656,29.625 11.0859,28.9219 Z M7.40625,20.0156 C7.40625,19.0312 6.58594,18.1875 5.57812,18.1875 L1.82812,18.1875 C0.820312,18.1875 0,19.0312 0,20.0156 C0,21 0.820312,21.8438 1.82812,21.8438 L5.57812,21.8438 C6.58594,21.8438 7.40625,21 7.40625,20.0156 Z M11.0625,11.1328 C11.7656,10.4531 11.7656,9.25781 11.0859,8.57812 L8.39062,5.85938 C7.71094,5.17969 6.51562,5.15625 5.83594,5.85938 C5.13281,6.5625 5.13281,7.75781 5.8125,8.4375 L8.48438,11.1328 C9.1875,11.8359 10.3594,11.8359 11.0625,11.1328 Z" id="形状" fill-opacity="0.85" fill="currentColor"></path>
|
61 |
+
<path d="M19.9688,29.5781 C25.1719,29.5781 29.5078,25.2656 29.5078,20.0156 C29.5078,14.7656 25.1719,10.4531 19.9688,10.4531 C14.7422,10.4531 10.4062,14.7656 10.4062,20.0156 C10.4062,25.2656 14.7422,29.5781 19.9688,29.5781 Z M19.9688,26.3906 C16.4766,26.3906 13.5938,23.4844 13.5938,20.0156 C13.5938,16.5469 16.4766,13.6406 19.9688,13.6406 C23.4375,13.6406 26.3203,16.5469 26.3203,20.0156 C26.3203,23.4844 23.4375,26.3906 19.9688,26.3906 Z" id="形状" fill-opacity="0.85" fill="currentColor"></path>
|
62 |
+
</g>
|
63 |
+
</g>
|
64 |
+
</svg>
|
65 |
+
</span>
|
66 |
+
<span class="show-on-light">
|
67 |
+
<svg width="24px" height="24px" viewBox="0 0 37.2422 42.2109" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
68 |
+
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
69 |
+
<g fill="currentColor" fill-rule="nonzero">
|
70 |
+
<path d="M30,21.6797 C30.375,21.6797 30.6562,21.3984 30.7031,21 C31.2422,16.1016 31.5469,15.9141 36.5156,15.1406 C36.9844,15.0703 37.2422,14.8594 37.2422,14.4375 C37.2422,14.0625 36.9844,13.8047 36.6094,13.7578 C31.5938,12.7969 31.2422,12.7969 30.7031,7.89844 C30.6562,7.47656 30.375,7.21875 30,7.21875 C29.6016,7.21875 29.3438,7.47656 29.2969,7.875 C28.6875,12.8672 28.4531,13.1016 23.3672,13.7578 C23.0156,13.7812 22.7344,14.0625 22.7344,14.4375 C22.7344,14.8359 23.0156,15.0703 23.3672,15.1406 C28.4531,16.1016 28.6641,16.1484 29.2969,21.0469 C29.3438,21.3984 29.6016,21.6797 30,21.6797 Z M21.2109,9 C21.4453,9 21.5859,8.85938 21.6328,8.625 C22.2422,5.60156 22.1719,5.55469 25.3359,4.92188 C25.5469,4.875 25.7109,4.75781 25.7109,4.5 C25.7109,4.24219 25.5469,4.125 25.3359,4.07812 C22.1719,3.44531 22.2422,3.39844 21.6328,0.375 C21.5859,0.140625 21.4453,0 21.2109,0 C20.9531,0 20.8125,0.140625 20.7656,0.375 C20.1562,3.39844 20.2266,3.44531 17.0859,4.07812 C16.8516,4.125 16.6875,4.24219 16.6875,4.5 C16.6875,4.75781 16.8516,4.875 17.0859,4.92188 C20.2266,5.55469 20.1797,5.60156 20.7656,8.625 C20.8125,8.85938 20.9531,9 21.2109,9 Z" fill-opacity="0.85"></path>
|
71 |
+
<path d="M16.3125,38.625 C23.1094,38.625 28.5938,35.1562 31.0781,29.2734 C31.4297,28.4062 31.3125,27.75 30.9141,27.3516 C30.5625,27 29.9531,26.9297 29.2734,27.2109 C27.8906,27.75 26.2031,28.0547 24.1406,28.0547 C16.0078,28.0547 10.7578,22.9453 10.7578,15.0938 C10.7578,12.7734 11.2031,10.5 11.7188,9.49219 C12.0938,8.69531 12.0703,8.01562 11.7422,7.61719 C11.3672,7.17188 10.7109,7.00781 9.77344,7.35938 C3.98438,9.58594 0,15.6562 0,22.5938 C0,31.6875 6.79688,38.625 16.3125,38.625 Z M16.3594,35.4141 C8.69531,35.4141 3.21094,29.8359 3.21094,22.3359 C3.21094,17.9766 5.08594,14.0391 8.29688,11.4375 C7.89844,12.6094 7.6875,14.3438 7.6875,16.0078 C7.6875,24.9844 14.0156,31.1484 23.2969,31.1484 C24.8203,31.1484 26.2266,30.9844 26.9062,30.7734 C24.6094,33.6562 20.6953,35.4141 16.3594,35.4141 Z" fill-opacity="0.85"></path>
|
72 |
+
</g>
|
73 |
+
</g>
|
74 |
+
</svg>
|
75 |
+
</span>
|
76 |
+
</button>
|
77 |
+
</div>
|
78 |
+
</div>
|
web_assets/html/header_title.html
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div style="display:inline-flex;">
|
2 |
+
<buttom id="chuanhu-menu-btn" onclick='menuClick()'
|
3 |
+
class="chuanhu-ui-btn hover-round-btn" style="visibility: visible; width:42px; height:42px; margin-right:5px;">
|
4 |
+
<svg viewBox="0 0 24 24" fill="currentColor">
|
5 |
+
<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path>
|
6 |
+
</svg>
|
7 |
+
</div>
|
8 |
+
<!-- <buttom class="gb_Ec gb_Ic gb_p" aria-label="Go back" title="Go back" role="button" tabindex="0">
|
9 |
+
<svg focusable="false" viewBox="0 0 24 24"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"></path>
|
10 |
+
</svg>
|
11 |
+
</buttom>
|
12 |
+
<div class="gb_Ec gb_Jc gb_p" aria-label="Close" role="button" tabindex="0"><svg viewBox="0 0 24 24">
|
13 |
+
<path
|
14 |
+
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z">
|
15 |
+
</path>
|
16 |
+
</svg></div> -->
|
17 |
+
<div style="margin-left: 6px;">
|
18 |
+
<div>{app_title}</div>
|
19 |
+
</div>
|
20 |
+
</div>
|
web_assets/html/web_config.html
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div aria-label="config-div" style="display:none;">
|
2 |
+
<!-- app config -->
|
3 |
+
<div id="app_config">
|
4 |
+
<span id="enableCheckUpdate_config">{enableCheckUpdate_config}</span>
|
5 |
+
<span id="hideHistoryWhenNotLoggedIn_config">{hideHistoryWhenNotLoggedIn_config}</span>
|
6 |
+
</div>
|
7 |
+
<!-- i18n config -->
|
8 |
+
<div id="config_i18n">
|
9 |
+
<span id="forView_i18n">{forView_i18n}</span>
|
10 |
+
<span id="deleteConfirm_i18n_pref">{deleteConfirm_i18n_pref}</span>
|
11 |
+
<span id="deleteConfirm_i18n_suff">{deleteConfirm_i18n_suff}</span>
|
12 |
+
<span id="usingLatest_i18n">{usingLatest_i18n}</span>
|
13 |
+
<span id="updatingMsg_i18n">{updatingMsg_i18n}</span>
|
14 |
+
<span id="updateSuccess_i18n">{updateSuccess_i18n}</span>
|
15 |
+
<span id="updateFailure_i18n">{updateFailure_i18n}</span>
|
16 |
+
<span id="regenerate_i18n">{regenerate_i18n}</span>
|
17 |
+
<span id="deleteRound_i18n">{deleteRound_i18n}</span>
|
18 |
+
<span id="renameChat_i18n">{renameChat_i18n}</span>
|
19 |
+
<span id="validFileName_i18n">{validFileName_i18n}</span>
|
20 |
+
</div>
|
21 |
+
</div>
|
web_assets/icon/any-icon-512.png
ADDED
web_assets/icon/mask-icon-512.png
ADDED
web_assets/javascript/ChuanhuChat.js
CHANGED
@@ -11,8 +11,11 @@ var user_input_ta = null;
|
|
11 |
var user_input_tb = null;
|
12 |
var userInfoDiv = null;
|
13 |
var appTitleDiv = null;
|
|
|
14 |
var chatbot = null;
|
15 |
var chatbotIndicator = null;
|
|
|
|
|
16 |
var chatbotWrap = null;
|
17 |
var apSwitch = null;
|
18 |
var messageBotDivs = null;
|
@@ -25,34 +28,52 @@ var sliders = null;
|
|
25 |
var updateChuanhuBtn = null;
|
26 |
var statusDisplay = null;
|
27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
var isInIframe = (window.self !== window.top);
|
29 |
var currentTime = new Date().getTime();
|
30 |
-
var initialized = false;
|
31 |
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
|
|
|
|
|
|
|
|
41 |
}
|
42 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
}
|
44 |
|
45 |
function initialize() {
|
46 |
-
|
47 |
-
initialized = true;
|
48 |
|
49 |
loginUserForm = gradioApp().querySelector(".gradio-container > .main > .wrap > .panel > .form")
|
50 |
gradioContainer = gradioApp().querySelector(".gradio-container");
|
51 |
user_input_tb = gradioApp().getElementById('user-input-tb');
|
52 |
userInfoDiv = gradioApp().getElementById("user-info");
|
53 |
appTitleDiv = gradioApp().getElementById("app-title");
|
|
|
54 |
chatbot = gradioApp().querySelector('#chuanhu-chatbot');
|
55 |
-
chatbotIndicator = gradioApp().querySelector('#chuanhu-chatbot>div.wrap');
|
56 |
chatbotWrap = gradioApp().querySelector('#chuanhu-chatbot > .wrapper > .wrap');
|
57 |
apSwitch = gradioApp().querySelector('.apSwitch input[type="checkbox"]');
|
58 |
updateToast = gradioApp().querySelector("#toast-update");
|
@@ -62,36 +83,50 @@ function initialize() {
|
|
62 |
updateChuanhuBtn = gradioApp().getElementById("update-chuanhu-btn");
|
63 |
statusDisplay = gradioApp().querySelector('#status-display');
|
64 |
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
|
|
|
|
|
|
|
|
|
|
69 |
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
}
|
75 |
-
}
|
76 |
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
}
|
96 |
|
97 |
function gradioApp() {
|
@@ -171,17 +206,49 @@ function disableSendBtn() {
|
|
171 |
});
|
172 |
}
|
173 |
|
174 |
-
function
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
|
|
|
|
|
|
|
|
179 |
} else {
|
180 |
-
|
181 |
-
document.body.style.backgroundColor = "";
|
182 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
183 |
}
|
184 |
-
|
|
|
185 |
const darkModeQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
186 |
apSwitch.checked = darkModeQuery.matches;
|
187 |
toggleDarkMode(darkModeQuery.matches);
|
@@ -193,8 +260,55 @@ function adjustDarkMode() {
|
|
193 |
toggleDarkMode(e.target.checked);
|
194 |
});
|
195 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
196 |
|
197 |
function setChatbotHeight() {
|
|
|
198 |
const screenWidth = window.innerWidth;
|
199 |
const statusDisplay = document.querySelector('#status-display');
|
200 |
const statusDisplayHeight = statusDisplay ? statusDisplay.offsetHeight : 0;
|
@@ -221,70 +335,94 @@ function setChatbotScroll() {
|
|
221 |
chatbotWrap.scrollTo(0,scrollHeight)
|
222 |
}
|
223 |
|
224 |
-
|
225 |
-
var userAvatarUrl = "";
|
226 |
-
function setAvatar() {
|
227 |
-
var botAvatar = gradioApp().getElementById("config-bot-avatar-url").innerText;
|
228 |
-
var userAvatar = gradioApp().getElementById("config-user-avatar-url").innerText;
|
229 |
-
|
230 |
-
if (botAvatar == "none") {
|
231 |
-
botAvatarUrl = "";
|
232 |
-
} else if (isImgUrl(botAvatar)) {
|
233 |
-
botAvatarUrl = botAvatar;
|
234 |
-
} else {
|
235 |
-
// botAvatarUrl = "https://github.com/GaiZhenbiao/ChuanhuChatGPT/assets/70903329/aca3a7ec-4f1d-4667-890c-a6f47bf08f63";
|
236 |
-
botAvatarUrl = "/file=web_assets/chatbot.png"
|
237 |
-
}
|
238 |
-
|
239 |
-
if (userAvatar == "none") {
|
240 |
-
userAvatarUrl = "";
|
241 |
-
} else if (isImgUrl(userAvatar)) {
|
242 |
-
userAvatarUrl = userAvatar;
|
243 |
-
} else {
|
244 |
-
userAvatarUrl = "data:image/svg+xml,%3Csvg width='32px' height='32px' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cg stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E%3Crect fill-opacity='0.5' fill='%23bbbbbb' x='0' y='0' width='32' height='32'%3E%3C/rect%3E%3Cg transform='translate(5, 4)' fill='%23999999' fill-opacity='0.8' fill-rule='nonzero'%3E%3Cpath d='M2.29372246,24 L19.7187739,24 C20.4277609,24 20.985212,23.8373915 21.3911272,23.5121746 C21.7970424,23.1869576 22,22.7418004 22,22.1767029 C22,21.3161536 21.7458721,20.4130827 21.2376163,19.4674902 C20.7293605,18.5218977 19.9956681,17.6371184 19.036539,16.8131524 C18.07741,15.9891863 16.9210688,15.3177115 15.5675154,14.798728 C14.2139621,14.2797445 12.6914569,14.0202527 11,14.0202527 C9.30854307,14.0202527 7.78603793,14.2797445 6.43248458,14.798728 C5.07893122,15.3177115 3.92259002,15.9891863 2.96346097,16.8131524 C2.00433193,17.6371184 1.27063951,18.5218977 0.762383704,19.4674902 C0.254127901,20.4130827 0,21.3161536 0,22.1767029 C0,22.7418004 0.202957595,23.1869576 0.608872784,23.5121746 C1.01478797,23.8373915 1.57640453,24 2.29372246,24 Z M11.0124963,11.6521659 C11.9498645,11.6521659 12.8155943,11.3906214 13.6096856,10.8675324 C14.403777,10.3444433 15.042131,9.63605539 15.5247478,8.74236856 C16.0073646,7.84868174 16.248673,6.84722464 16.248673,5.73799727 C16.248673,4.65135034 16.0071492,3.67452644 15.5241015,2.80752559 C15.0410538,1.94052474 14.4024842,1.25585359 13.6083929,0.753512156 C12.8143016,0.251170719 11.9490027,0 11.0124963,0 C10.0759899,0 9.20860836,0.255422879 8.41035158,0.766268638 C7.6120948,1.2771144 6.97352528,1.96622098 6.49464303,2.8335884 C6.01576078,3.70095582 5.77631966,4.67803631 5.77631966,5.76482987 C5.77631966,6.86452653 6.01554533,7.85912886 6.49399667,8.74863683 C6.97244801,9.63814481 7.60871935,10.3444433 8.40281069,10.8675324 C9.19690203,11.3906214 10.0667972,11.6521659 11.0124963,11.6521659 Z'%3E%3C/path%3E%3C/g%3E%3C/g%3E%3C/svg%3E";
|
245 |
-
}
|
246 |
-
}
|
247 |
-
|
248 |
-
function clearChatbot() {
|
249 |
clearHistoryHtml();
|
250 |
-
clearMessageRows();
|
|
|
251 |
}
|
252 |
|
253 |
-
function chatbotContentChanged(attempt = 1) {
|
254 |
for (var i = 0; i < attempt; i++) {
|
255 |
setTimeout(() => {
|
256 |
// clearMessageRows();
|
257 |
saveHistoryHtml();
|
258 |
disableSendBtn();
|
259 |
-
|
260 |
-
gradioApp().querySelectorAll('#chuanhu-chatbot .message-wrap .message.bot').forEach(
|
261 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
262 |
}
|
263 |
// 理论上是不需要多次尝试执行的,可惜gradio的bug导致message可能没有渲染完毕,所以尝试500ms后再次执行
|
264 |
}
|
265 |
|
266 |
var chatbotObserver = new MutationObserver(() => {
|
267 |
-
clearMessageRows();
|
268 |
chatbotContentChanged(1);
|
269 |
if (chatbotIndicator.classList.contains('hide')) {
|
|
|
|
|
|
|
|
|
270 |
chatbotContentChanged(2);
|
271 |
}
|
|
|
|
|
|
|
|
|
|
|
272 |
});
|
273 |
|
274 |
// 监视页面内部 DOM 变动
|
275 |
-
var
|
276 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
277 |
});
|
278 |
|
279 |
// 监视页面变化
|
280 |
window.addEventListener("DOMContentLoaded", function () {
|
281 |
-
const ga = document.getElementsByTagName("gradio-app");
|
282 |
-
|
|
|
|
|
283 |
isInIframe = (window.self !== window.top);
|
284 |
historyLoaded = false;
|
285 |
});
|
286 |
-
window.addEventListener('resize',
|
287 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
288 |
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", adjustDarkMode);
|
289 |
|
290 |
// console suprise
|
@@ -303,13 +441,13 @@ function makeML(str) {
|
|
303 |
return l
|
304 |
}
|
305 |
let ChuanhuInfo = function () {
|
306 |
-
/*
|
307 |
-
________ __ ________ __
|
308 |
/ ____/ /_ __ ______ _____ / /_ __ __ / ____/ /_ ____ _/ /_
|
309 |
/ / / __ \/ / / / __ `/ __ \/ __ \/ / / / / / / __ \/ __ `/ __/
|
310 |
-
/ /___/ / / / /_/ / /_/ / / / / / / / /_/ / / /___/ / / / /_/ / /_
|
311 |
-
\____/_/ /_/\__,_/\__,_/_/ /_/_/ /_/\__,_/ \____/_/ /_/\__,_/\__/
|
312 |
-
|
313 |
川虎Chat (Chuanhu Chat) - GUI for ChatGPT API and many LLMs
|
314 |
*/
|
315 |
}
|
@@ -318,11 +456,5 @@ let description = `
|
|
318 |
GitHub repository: [https://github.com/GaiZhenbiao/ChuanhuChatGPT]\n
|
319 |
Enjoy our project!\n
|
320 |
`
|
321 |
-
console.log(`%c${makeML(ChuanhuInfo)}`,styleTitle1)
|
322 |
-
console.log(`%c${description}`, styleDesc1)
|
323 |
-
|
324 |
-
// button svg code
|
325 |
-
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>';
|
326 |
-
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>';
|
327 |
-
const mdIcon = '<span><svg stroke="currentColor" fill="none" stroke-width="1" viewBox="0 0 14 18" stroke-linecap="round" stroke-linejoin="round" height=".8em" width=".8em" xmlns="http://www.w3.org/2000/svg"><g transform-origin="center" transform="scale(0.85)"><path d="M1.5,0 L12.5,0 C13.3284271,-1.52179594e-16 14,0.671572875 14,1.5 L14,16.5 C14,17.3284271 13.3284271,18 12.5,18 L1.5,18 C0.671572875,18 1.01453063e-16,17.3284271 0,16.5 L0,1.5 C-1.01453063e-16,0.671572875 0.671572875,1.52179594e-16 1.5,0 Z" stroke-width="1.8"></path><line x1="3.5" y1="3.5" x2="10.5" y2="3.5"></line><line x1="3.5" y1="6.5" x2="8" y2="6.5"></line></g><path d="M4,9 L10,9 C10.5522847,9 11,9.44771525 11,10 L11,13.5 C11,14.0522847 10.5522847,14.5 10,14.5 L4,14.5 C3.44771525,14.5 3,14.0522847 3,13.5 L3,10 C3,9.44771525 3.44771525,9 4,9 Z" stroke="none" fill="currentColor"></path></svg></span>';
|
328 |
-
const rawIcon = '<span><svg stroke="currentColor" fill="none" stroke-width="1.8" viewBox="0 0 18 14" stroke-linecap="round" stroke-linejoin="round" height=".8em" width=".8em" xmlns="http://www.w3.org/2000/svg"><g transform-origin="center" transform="scale(0.85)"><polyline points="4 3 0 7 4 11"></polyline><polyline points="14 3 18 7 14 11"></polyline><line x1="12" y1="0" x2="6" y2="14"></line></g></svg></span>';
|
|
|
11 |
var user_input_tb = null;
|
12 |
var userInfoDiv = null;
|
13 |
var appTitleDiv = null;
|
14 |
+
var chatbotArea = null;
|
15 |
var chatbot = null;
|
16 |
var chatbotIndicator = null;
|
17 |
+
var uploaderIndicator = null;
|
18 |
+
var chatListIndicator = null;
|
19 |
var chatbotWrap = null;
|
20 |
var apSwitch = null;
|
21 |
var messageBotDivs = null;
|
|
|
28 |
var updateChuanhuBtn = null;
|
29 |
var statusDisplay = null;
|
30 |
|
31 |
+
var historySelector = null;
|
32 |
+
var chuanhuPopup = null;
|
33 |
+
var settingBox = null;
|
34 |
+
var trainingBox = null;
|
35 |
+
var popupWrapper = null;
|
36 |
+
var chuanhuHeader = null;
|
37 |
+
var menu = null;
|
38 |
+
var toolbox = null;
|
39 |
+
// var trainBody = null;
|
40 |
+
|
41 |
var isInIframe = (window.self !== window.top);
|
42 |
var currentTime = new Date().getTime();
|
|
|
43 |
|
44 |
+
let windowWidth = window.innerWidth; // 初始窗口宽度
|
45 |
+
|
46 |
+
function addInit() {
|
47 |
+
var needInit = {chatbotIndicator, uploaderIndicator};
|
48 |
+
|
49 |
+
chatbotIndicator = gradioApp().querySelector('#chuanhu-chatbot > div.wrap');
|
50 |
+
uploaderIndicator = gradioApp().querySelector('#upload-index-file > div.wrap');
|
51 |
+
chatListIndicator = gradioApp().querySelector('#history-select-dropdown > div.wrap');
|
52 |
+
|
53 |
+
for (let elem in needInit) {
|
54 |
+
if (needInit[elem] == null) {
|
55 |
+
// addInited = false;
|
56 |
+
return false;
|
57 |
}
|
58 |
}
|
59 |
+
|
60 |
+
chatbotObserver.observe(chatbotIndicator, { attributes: true, childList: true, subtree: true });
|
61 |
+
chatListObserver.observe(chatListIndicator, { attributes: true });
|
62 |
+
setUploader();
|
63 |
+
|
64 |
+
return true;
|
65 |
}
|
66 |
|
67 |
function initialize() {
|
68 |
+
gradioObserver.observe(gradioApp(), { childList: true, subtree: true });
|
|
|
69 |
|
70 |
loginUserForm = gradioApp().querySelector(".gradio-container > .main > .wrap > .panel > .form")
|
71 |
gradioContainer = gradioApp().querySelector(".gradio-container");
|
72 |
user_input_tb = gradioApp().getElementById('user-input-tb');
|
73 |
userInfoDiv = gradioApp().getElementById("user-info");
|
74 |
appTitleDiv = gradioApp().getElementById("app-title");
|
75 |
+
chatbotArea = gradioApp().querySelector('#chatbot-area');
|
76 |
chatbot = gradioApp().querySelector('#chuanhu-chatbot');
|
|
|
77 |
chatbotWrap = gradioApp().querySelector('#chuanhu-chatbot > .wrapper > .wrap');
|
78 |
apSwitch = gradioApp().querySelector('.apSwitch input[type="checkbox"]');
|
79 |
updateToast = gradioApp().querySelector("#toast-update");
|
|
|
83 |
updateChuanhuBtn = gradioApp().getElementById("update-chuanhu-btn");
|
84 |
statusDisplay = gradioApp().querySelector('#status-display');
|
85 |
|
86 |
+
historySelector = gradioApp().querySelector('#history-select-dropdown');
|
87 |
+
chuanhuPopup = gradioApp().querySelector('#chuanhu-popup');
|
88 |
+
settingBox = gradioApp().querySelector('#chuanhu-setting');
|
89 |
+
trainingBox = gradioApp().querySelector('#chuanhu-training');
|
90 |
+
popupWrapper = gradioApp().querySelector('#popup-wrapper');
|
91 |
+
chuanhuHeader = gradioApp().querySelector('#chuanhu-header');
|
92 |
+
menu = gradioApp().querySelector('#menu-area');
|
93 |
+
toolbox = gradioApp().querySelector('#toolbox-area');
|
94 |
+
// trainBody = gradioApp().querySelector('#train-body');
|
95 |
|
96 |
+
// if (loginUserForm) {
|
97 |
+
// localStorage.setItem("userLogged", true);
|
98 |
+
// userLogged = true;
|
99 |
+
// }
|
|
|
|
|
100 |
|
101 |
+
adjustDarkMode();
|
102 |
+
adjustSide();
|
103 |
+
setChatList();
|
104 |
+
setChatListHeader();
|
105 |
+
setLoclize();
|
106 |
+
selectHistory();
|
107 |
+
// setChatbotHeight();
|
108 |
+
setPopupBoxPosition();
|
109 |
+
setSlider();
|
110 |
+
setCheckboxes();
|
111 |
+
checkModel();
|
112 |
+
|
113 |
+
settingBox.classList.add('hideBox');
|
114 |
+
trainingBox.classList.add('hideBox');
|
115 |
+
|
116 |
+
if (!historyLoaded) loadHistoryHtml();
|
117 |
+
if (!usernameGotten) getUserInfo();
|
118 |
+
|
119 |
+
setUpdater();
|
120 |
+
|
121 |
+
setChatbotScroll();
|
122 |
+
setTimeout(showOrHideUserInfo(), 2000);
|
123 |
+
|
124 |
+
// setHistroyPanel();
|
125 |
+
// trainBody.classList.add('hide-body');
|
126 |
+
|
127 |
+
|
128 |
+
|
129 |
+
return true;
|
130 |
}
|
131 |
|
132 |
function gradioApp() {
|
|
|
206 |
});
|
207 |
}
|
208 |
|
209 |
+
function checkModel() {
|
210 |
+
const model = gradioApp().querySelector('#model-select-dropdown input');
|
211 |
+
var modelValue = model.value;
|
212 |
+
checkGPT();
|
213 |
+
checkXMChat();
|
214 |
+
function checkGPT() {
|
215 |
+
modelValue = model.value;
|
216 |
+
if (modelValue.toLowerCase().includes('gpt')) {
|
217 |
+
gradioApp().querySelector('#header-btn-groups').classList.add('is-gpt');
|
218 |
} else {
|
219 |
+
gradioApp().querySelector('#header-btn-groups').classList.remove('is-gpt');
|
|
|
220 |
}
|
221 |
+
// console.log('gpt model checked')
|
222 |
+
}
|
223 |
+
function checkXMChat() {
|
224 |
+
modelValue = model.value;
|
225 |
+
if (modelValue.includes('xmchat')) {
|
226 |
+
chatbotArea.classList.add('is-xmchat');
|
227 |
+
} else {
|
228 |
+
chatbotArea.classList.remove('is-xmchat');
|
229 |
+
}
|
230 |
+
}
|
231 |
+
|
232 |
+
model.addEventListener('blur', ()=>{
|
233 |
+
setTimeout(()=>{
|
234 |
+
checkGPT();
|
235 |
+
checkXMChat();
|
236 |
+
}, 100);
|
237 |
+
});
|
238 |
+
}
|
239 |
+
|
240 |
+
function toggleDarkMode(isEnabled) {
|
241 |
+
if (isEnabled) {
|
242 |
+
document.body.classList.add("dark");
|
243 |
+
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#171717');
|
244 |
+
document.body.style.setProperty("background-color", "var(--neutral-950)", "important");
|
245 |
+
} else {
|
246 |
+
document.body.classList.remove("dark");
|
247 |
+
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff');
|
248 |
+
document.body.style.backgroundColor = "";
|
249 |
}
|
250 |
+
}
|
251 |
+
function adjustDarkMode() {
|
252 |
const darkModeQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
253 |
apSwitch.checked = darkModeQuery.matches;
|
254 |
toggleDarkMode(darkModeQuery.matches);
|
|
|
260 |
toggleDarkMode(e.target.checked);
|
261 |
});
|
262 |
}
|
263 |
+
function btnToggleDarkMode() {
|
264 |
+
apSwitch.checked = !apSwitch.checked;
|
265 |
+
toggleDarkMode(apSwitch.checked);
|
266 |
+
}
|
267 |
+
|
268 |
+
function setScrollShadow() {
|
269 |
+
const toolboxScroll = toolbox.querySelector('#toolbox-area > .gradio-box > .gradio-tabs > div.tab-nav');
|
270 |
+
const toolboxTabs = toolboxScroll.querySelectorAll('button');
|
271 |
+
let toolboxScrollWidth = 0;
|
272 |
+
toolboxTabs.forEach((tab) => {
|
273 |
+
toolboxScrollWidth += tab.offsetWidth; // 获取按钮宽度并累加
|
274 |
+
});
|
275 |
+
function adjustScrollShadow() {
|
276 |
+
if (toolboxScroll.scrollLeft > 0) {
|
277 |
+
toolboxScroll.classList.add('scroll-shadow-left');
|
278 |
+
} else {
|
279 |
+
toolboxScroll.classList.remove('scroll-shadow-left');
|
280 |
+
}
|
281 |
+
|
282 |
+
if (toolboxScroll.scrollLeft + toolboxScroll.clientWidth < toolboxScrollWidth) {
|
283 |
+
toolboxScroll.classList.add('scroll-shadow-right');
|
284 |
+
} else {
|
285 |
+
toolboxScroll.classList.remove('scroll-shadow-right');
|
286 |
+
}
|
287 |
+
}
|
288 |
+
toolboxScroll.addEventListener('scroll', () => {
|
289 |
+
adjustScrollShadow();
|
290 |
+
});
|
291 |
+
// no, I failed to make shadow appear on the top layer...
|
292 |
+
}
|
293 |
+
|
294 |
+
function setPopupBoxPosition() {
|
295 |
+
const screenWidth = window.innerWidth;
|
296 |
+
const screenHeight = window.innerHeight;
|
297 |
+
popupWrapper.style.height = `${screenHeight}px`;
|
298 |
+
popupWrapper.style.width = `${screenWidth}px`;
|
299 |
+
// const popupBoxWidth = 680;
|
300 |
+
// const popupBoxHeight = 400;
|
301 |
+
// chuanhuPopup.style.left = `${(screenWidth - popupBoxWidth) / 2}px`;
|
302 |
+
// chuanhuPopup.style.top = `${(screenHeight - popupBoxHeight) / 2}px`;
|
303 |
+
}
|
304 |
+
|
305 |
+
function updateVH() {
|
306 |
+
const vh = window.innerHeight * 0.01;
|
307 |
+
document.documentElement.style.setProperty('--vh', `${vh}px`);
|
308 |
+
}
|
309 |
|
310 |
function setChatbotHeight() {
|
311 |
+
return;
|
312 |
const screenWidth = window.innerWidth;
|
313 |
const statusDisplay = document.querySelector('#status-display');
|
314 |
const statusDisplayHeight = statusDisplay ? statusDisplay.offsetHeight : 0;
|
|
|
335 |
chatbotWrap.scrollTo(0,scrollHeight)
|
336 |
}
|
337 |
|
338 |
+
function clearChatbot(a, b) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
339 |
clearHistoryHtml();
|
340 |
+
// clearMessageRows();
|
341 |
+
return [a, b]
|
342 |
}
|
343 |
|
344 |
+
function chatbotContentChanged(attempt = 1, force = false) {
|
345 |
for (var i = 0; i < attempt; i++) {
|
346 |
setTimeout(() => {
|
347 |
// clearMessageRows();
|
348 |
saveHistoryHtml();
|
349 |
disableSendBtn();
|
350 |
+
|
351 |
+
gradioApp().querySelectorAll('#chuanhu-chatbot .message-wrap .message.bot').forEach(addChuanhuButton);
|
352 |
+
|
353 |
+
if (chatbotIndicator.classList.contains('hide')) { // generation finished
|
354 |
+
setLatestMessage();
|
355 |
+
setChatList();
|
356 |
+
}
|
357 |
+
|
358 |
+
if (!chatbotIndicator.classList.contains('translucent')) { // message deleted
|
359 |
+
var checkLatestAdded = setInterval(() => {
|
360 |
+
var latestMessageNow = gradioApp().querySelector('#chuanhu-chatbot > .wrapper > .wrap > .message-wrap .message.bot.latest');
|
361 |
+
if (latestMessageNow && latestMessageNow.querySelector('.message-btn-row')) {
|
362 |
+
clearInterval(checkLatestAdded);
|
363 |
+
} else {
|
364 |
+
setLatestMessage();
|
365 |
+
}
|
366 |
+
}, 200);
|
367 |
+
}
|
368 |
+
|
369 |
+
|
370 |
+
}, i === 0 ? 0 : 200);
|
371 |
}
|
372 |
// 理论上是不需要多次尝试执行的,可惜gradio的bug导致message可能没有渲染完毕,所以尝试500ms后再次执行
|
373 |
}
|
374 |
|
375 |
var chatbotObserver = new MutationObserver(() => {
|
|
|
376 |
chatbotContentChanged(1);
|
377 |
if (chatbotIndicator.classList.contains('hide')) {
|
378 |
+
// setLatestMessage();
|
379 |
+
chatbotContentChanged(2);
|
380 |
+
}
|
381 |
+
if (!chatbotIndicator.classList.contains('translucent')) {
|
382 |
chatbotContentChanged(2);
|
383 |
}
|
384 |
+
|
385 |
+
});
|
386 |
+
|
387 |
+
var chatListObserver = new MutationObserver(() => {
|
388 |
+
setChatList();
|
389 |
});
|
390 |
|
391 |
// 监视页面内部 DOM 变动
|
392 |
+
var gradioObserver = new MutationObserver(function (mutations) {
|
393 |
+
for (var i = 0; i < mutations.length; i++) {
|
394 |
+
if (mutations[i].addedNodes.length) {
|
395 |
+
if (addInit()) {
|
396 |
+
gradioObserver.disconnect();
|
397 |
+
return;
|
398 |
+
}
|
399 |
+
}
|
400 |
+
}
|
401 |
});
|
402 |
|
403 |
// 监视页面变化
|
404 |
window.addEventListener("DOMContentLoaded", function () {
|
405 |
+
// const ga = document.getElementsByTagName("gradio-app");
|
406 |
+
updateVH();
|
407 |
+
windowWidth = window.innerWidth;
|
408 |
+
gradioApp().addEventListener("render", initialize);
|
409 |
isInIframe = (window.self !== window.top);
|
410 |
historyLoaded = false;
|
411 |
});
|
412 |
+
window.addEventListener('resize', ()=>{
|
413 |
+
// setChatbotHeight();
|
414 |
+
updateVH();
|
415 |
+
windowWidth = window.innerWidth;
|
416 |
+
setPopupBoxPosition();
|
417 |
+
adjustSide();
|
418 |
+
});
|
419 |
+
window.addEventListener('orientationchange', (event) => {
|
420 |
+
updateVH();
|
421 |
+
windowWidth = window.innerWidth;
|
422 |
+
setPopupBoxPosition();
|
423 |
+
adjustSide();
|
424 |
+
});
|
425 |
+
window.addEventListener('scroll', ()=>{setPopupBoxPosition();});
|
426 |
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", adjustDarkMode);
|
427 |
|
428 |
// console suprise
|
|
|
441 |
return l
|
442 |
}
|
443 |
let ChuanhuInfo = function () {
|
444 |
+
/*
|
445 |
+
________ __ ________ __
|
446 |
/ ____/ /_ __ ______ _____ / /_ __ __ / ____/ /_ ____ _/ /_
|
447 |
/ / / __ \/ / / / __ `/ __ \/ __ \/ / / / / / / __ \/ __ `/ __/
|
448 |
+
/ /___/ / / / /_/ / /_/ / / / / / / / /_/ / / /___/ / / / /_/ / /_
|
449 |
+
\____/_/ /_/\__,_/\__,_/_/ /_/_/ /_/\__,_/ \____/_/ /_/\__,_/\__/
|
450 |
+
|
451 |
川虎Chat (Chuanhu Chat) - GUI for ChatGPT API and many LLMs
|
452 |
*/
|
453 |
}
|
|
|
456 |
GitHub repository: [https://github.com/GaiZhenbiao/ChuanhuChatGPT]\n
|
457 |
Enjoy our project!\n
|
458 |
`
|
459 |
+
console.log(`%c${makeML(ChuanhuInfo)}`,styleTitle1);
|
460 |
+
console.log(`%c${description}`, styleDesc1);
|
|
|
|
|
|
|
|
|
|
|
|