JohnSmith9982 commited on
Commit
4dfaeff
1 Parent(s): 632a25e

Upload 114 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. CITATION.cff +5 -5
  2. ChuanhuChatbot.py +152 -66
  3. Dockerfile +11 -8
  4. config_example.json +55 -14
  5. locale/en_US.json +23 -9
  6. locale/ja_JP.json +23 -9
  7. locale/ko_KR.json +89 -0
  8. locale/sv-SE.json +87 -0
  9. modules/.DS_Store +0 -0
  10. modules/__pycache__/config.cpython-311.pyc +0 -0
  11. modules/__pycache__/config.cpython-39.pyc +0 -0
  12. modules/__pycache__/index_func.cpython-311.pyc +0 -0
  13. modules/__pycache__/index_func.cpython-39.pyc +0 -0
  14. modules/__pycache__/overwrites.cpython-311.pyc +0 -0
  15. modules/__pycache__/overwrites.cpython-39.pyc +0 -0
  16. modules/__pycache__/pdf_func.cpython-311.pyc +0 -0
  17. modules/__pycache__/presets.cpython-311.pyc +0 -0
  18. modules/__pycache__/presets.cpython-39.pyc +0 -0
  19. modules/__pycache__/repo.cpython-311.pyc +0 -0
  20. modules/__pycache__/shared.cpython-311.pyc +0 -0
  21. modules/__pycache__/shared.cpython-39.pyc +0 -0
  22. modules/__pycache__/train_func.cpython-311.pyc +0 -0
  23. modules/__pycache__/utils.cpython-311.pyc +0 -0
  24. modules/__pycache__/utils.cpython-39.pyc +0 -0
  25. modules/__pycache__/webui.cpython-311.pyc +0 -0
  26. modules/config.py +123 -33
  27. modules/index_func.py +15 -20
  28. modules/models/Google_PaLM.py +26 -0
  29. modules/models/__pycache__/ChuanhuAgent.cpython-311.pyc +0 -0
  30. modules/models/__pycache__/Google_PaLM.cpython-311.pyc +0 -0
  31. modules/models/__pycache__/azure.cpython-311.pyc +0 -0
  32. modules/models/__pycache__/base_model.cpython-311.pyc +0 -0
  33. modules/models/__pycache__/base_model.cpython-39.pyc +0 -0
  34. modules/models/__pycache__/models.cpython-311.pyc +0 -0
  35. modules/models/__pycache__/models.cpython-39.pyc +0 -0
  36. modules/models/azure.py +17 -0
  37. modules/models/base_model.py +130 -28
  38. modules/models/midjourney.py +385 -0
  39. modules/models/models.py +34 -17
  40. modules/overwrites.py +33 -20
  41. modules/presets.py +10 -2
  42. modules/repo.py +239 -0
  43. modules/shared.py +1 -0
  44. modules/train_func.py +161 -0
  45. modules/utils.py +85 -58
  46. modules/webui.py +70 -0
  47. readme/README_en.md +21 -8
  48. readme/README_ja.md +21 -8
  49. requirements.txt +8 -5
  50. requirements_advanced.txt +11 -0
CITATION.cff CHANGED
@@ -1,5 +1,5 @@
1
  cff-version: 1.2.0
2
- title: ChuanhuChatGPT
3
  message: >-
4
  If you use this software, please cite it using these
5
  metadata.
@@ -13,8 +13,8 @@ authors:
13
  orcid: https://orcid.org/0009-0005-0357-272X
14
  repository-code: 'https://github.com/GaiZhenbiao/ChuanhuChatGPT'
15
  url: 'https://github.com/GaiZhenbiao/ChuanhuChatGPT'
16
- abstract: Provided a light and easy to use interface for ChatGPT API
17
  license: GPL-3.0
18
- commit: bd0034c37e5af6a90bd9c2f7dd073f6cd27c61af
19
- version: '20230405'
20
- date-released: '2023-04-05'
1
  cff-version: 1.2.0
2
+ title: Chuanhu Chat
3
  message: >-
4
  If you use this software, please cite it using these
5
  metadata.
13
  orcid: https://orcid.org/0009-0005-0357-272X
14
  repository-code: 'https://github.com/GaiZhenbiao/ChuanhuChatGPT'
15
  url: 'https://github.com/GaiZhenbiao/ChuanhuChatGPT'
16
+ abstract: This software provides a light and easy-to-use interface for ChatGPT API and many LLMs.
17
  license: GPL-3.0
18
+ commit: c6c08bc62ef80e37c8be52f65f9b6051a7eea1fa
19
+ version: '20230709'
20
+ date-released: '2023-07-09'
ChuanhuChatbot.py CHANGED
@@ -1,8 +1,11 @@
1
  # -*- coding:utf-8 -*-
2
- import os
3
  import logging
4
- import sys
 
 
 
5
 
 
6
  import gradio as gr
7
 
8
  from modules import config
@@ -10,6 +13,9 @@ from modules.config import *
10
  from modules.utils import *
11
  from modules.presets import *
12
  from modules.overwrites import *
 
 
 
13
  from modules.models.models import get_model
14
 
15
  logging.getLogger("httpx").setLevel(logging.WARNING)
@@ -17,13 +23,13 @@ logging.getLogger("httpx").setLevel(logging.WARNING)
17
  gr.Chatbot._postprocess_chat_messages = postprocess_chat_messages
18
  gr.Chatbot.postprocess = postprocess
19
 
20
- with open("assets/custom.css", "r", encoding="utf-8") as f:
21
- customCSS = f.read()
22
 
23
  def create_new_model():
24
  return get_model(model_name = MODELS[DEFAULT_MODEL], access_key = my_api_key)[0]
25
 
26
- with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
27
  user_name = gr.State("")
28
  promptTemplates = gr.State(load_template(get_template_names(plain=True)[0], mode=2))
29
  user_question = gr.State("")
@@ -34,31 +40,45 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
34
  topic = gr.State(i18n("未命名对话历史记录"))
35
 
36
  with gr.Row():
37
- gr.HTML(CHUANHU_TITLE, elem_id="app_title")
38
- status_display = gr.Markdown(get_geoip(), elem_id="status_display")
39
- with gr.Row(elem_id="float_display"):
40
- user_info = gr.Markdown(value="getting user info...", elem_id="user_info")
41
-
42
- with gr.Row().style(equal_height=True):
 
 
 
 
 
 
 
 
 
43
  with gr.Column(scale=5):
44
  with gr.Row():
45
- chatbot = gr.Chatbot(label="Chuanhu Chat", elem_id="chuanhu_chatbot").style(height="100%")
46
  with gr.Row():
47
  with gr.Column(min_width=225, scale=12):
48
  user_input = gr.Textbox(
49
- elem_id="user_input_tb",
50
- show_label=False, placeholder=i18n("在这里输入")
51
- ).style(container=False)
 
52
  with gr.Column(min_width=42, scale=1):
53
- submitBtn = gr.Button(value="", variant="primary", elem_id="submit_btn")
54
- cancelBtn = gr.Button(value="", variant="secondary", visible=False, elem_id="cancel_btn")
55
- with gr.Row():
56
- emptyBtn = gr.Button(
57
- i18n("🧹 新的对话"), elem_id="empty_btn"
58
- )
59
- retryBtn = gr.Button(i18n("🔄 重新生成"))
60
- delFirstBtn = gr.Button(i18n("🗑️ 删除最旧对话"))
61
- delLastBtn = gr.Button(i18n("🗑️ 删除最新对话"))
 
 
 
 
62
  with gr.Row(visible=False) as like_dislike_area:
63
  with gr.Column(min_width=20, scale=1):
64
  likeBtn = gr.Button(i18n("👍"))
@@ -77,9 +97,9 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
77
  label="API-Key",
78
  )
79
  if multi_api_key:
80
- usageTxt = gr.Markdown(i18n("多账号模式已开启,无需输入key,可直接开始对话"), elem_id="usage_display", elem_classes="insert_block")
81
  else:
82
- usageTxt = gr.Markdown(i18n("**发送消息** 或 **提交key** 以显示额度"), elem_id="usage_display", elem_classes="insert_block")
83
  model_select_dropdown = gr.Dropdown(
84
  label=i18n("选择模型"), choices=MODELS, multiselect=False, value=MODELS[DEFAULT_MODEL], interactive=True
85
  )
@@ -87,15 +107,15 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
87
  label=i18n("选择LoRA模型"), choices=[], multiselect=False, interactive=True, visible=False
88
  )
89
  with gr.Row():
90
- single_turn_checkbox = gr.Checkbox(label=i18n("单轮对话"), value=False)
91
- use_websearch_checkbox = gr.Checkbox(label=i18n("使用在线搜索"), value=False)
92
  language_select_dropdown = gr.Dropdown(
93
  label=i18n("选择回复语言(针对搜索&索引功能)"),
94
  choices=REPLY_LANGUAGES,
95
  multiselect=False,
96
  value=REPLY_LANGUAGES[0],
97
  )
98
- index_files = gr.Files(label=i18n("上传"), type="file")
99
  two_column = gr.Checkbox(label=i18n("双栏pdf"), value=advance_docs["pdf"].get("two_column", False))
100
  summarize_btn = gr.Button(i18n("总结"))
101
  # TODO: 公式ocr
@@ -107,8 +127,8 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
107
  placeholder=i18n("在这里输入System Prompt..."),
108
  label="System prompt",
109
  value=INITIAL_SYSTEM_PROMPT,
110
- lines=10,
111
- ).style(container=False)
112
  with gr.Accordion(label=i18n("加载Prompt模板"), open=True):
113
  with gr.Column():
114
  with gr.Row():
@@ -118,7 +138,8 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
118
  choices=get_template_names(plain=True),
119
  multiselect=False,
120
  value=get_template_names(plain=True)[0],
121
- ).style(container=False)
 
122
  with gr.Column(scale=1):
123
  templateRefreshBtn = gr.Button(i18n("🔄 刷新"))
124
  with gr.Row():
@@ -129,7 +150,8 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
129
  get_template_names(plain=True)[0], mode=1
130
  ),
131
  multiselect=False,
132
- ).style(container=False)
 
133
 
134
  with gr.Tab(label=i18n("保存/加载")):
135
  with gr.Accordion(label=i18n("保存/加载对话历史记录"), open=True):
@@ -139,10 +161,14 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
139
  historyFileSelectDropdown = gr.Dropdown(
140
  label=i18n("从列表中加载对话"),
141
  choices=get_history_names(plain=True),
142
- multiselect=False
 
143
  )
144
- with gr.Column(scale=1):
145
- historyRefreshBtn = gr.Button(i18n("🔄 刷新"))
 
 
 
146
  with gr.Row():
147
  with gr.Column(scale=6):
148
  saveFileName = gr.Textbox(
@@ -150,7 +176,9 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
150
  placeholder=i18n("设置文件名: 默认为.json,可选为.md"),
151
  label=i18n("设置保存文件名"),
152
  value=i18n("对话历史记录"),
153
- ).style(container=True)
 
 
154
  with gr.Column(scale=1):
155
  saveHistoryBtn = gr.Button(i18n("💾 保存对话"))
156
  exportMarkdownBtn = gr.Button(i18n("📝 导出为Markdown"))
@@ -159,12 +187,32 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
159
  with gr.Column():
160
  downloadFile = gr.File(interactive=True)
161
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  with gr.Tab(label=i18n("高级")):
163
- gr.Markdown(i18n("# ⚠️ 务必谨慎更改 ⚠️\n\n如果无法使用请恢复默认设置"))
164
- gr.HTML(get_html("appearance_switcher.html").format(label=i18n("切换亮暗色主题")), elem_classes="insert_block")
165
  use_streaming_checkbox = gr.Checkbox(
166
- label=i18n("实时传输回答"), value=True, visible=ENABLE_STREAMING_OPTION
167
  )
 
 
168
  with gr.Accordion(i18n("参数"), open=False):
169
  temperature_slider = gr.Slider(
170
  minimum=-0,
@@ -192,7 +240,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
192
  )
193
  stop_sequence_txt = gr.Textbox(
194
  show_label=True,
195
- placeholder=i18n("在这里输入停止符,用英文逗号隔开..."),
196
  label="stop",
197
  value="",
198
  lines=1,
@@ -244,25 +292,36 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
244
  lines=1,
245
  )
246
 
247
- with gr.Accordion(i18n("网络设置"), open=False, visible=False):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  # 优先展示自定义的api_host
249
  apihostTxt = gr.Textbox(
250
  show_label=True,
251
- placeholder=i18n("在这里输入API-Host..."),
252
- label="API-Host",
253
  value=config.api_host or shared.API_HOST,
254
  lines=1,
 
 
 
255
  )
256
- changeAPIURLBtn = gr.Button(i18n("🔄 切换API地址"))
257
- proxyTxt = gr.Textbox(
258
- show_label=True,
259
- placeholder=i18n("在这里输入代理地址..."),
260
- label=i18n("代理地址(示例:http://127.0.0.1:10809)"),
261
- value="",
262
- lines=2,
263
- )
264
- changeProxyBtn = gr.Button(i18n("🔄 设置代理地址"))
265
- default_btn = gr.Button(i18n("🔙 恢复默认设置"))
266
 
267
  gr.Markdown(CHUANHU_DESCRIPTION, elem_id="description")
268
  gr.HTML(get_html("footer.html").format(versions=versions_html()), elem_id="footer")
@@ -323,6 +382,10 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
323
  outputs=[saveFileName, systemPromptTxt, chatbot]
324
  )
325
 
 
 
 
 
326
 
327
  # Chatbot
328
  cancelBtn.click(interrupt, [current_model], [])
@@ -341,6 +404,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
341
  inputs=[current_model],
342
  outputs=[chatbot, status_display],
343
  show_progress=True,
 
344
  )
345
 
346
  retryBtn.click(**start_outputing_args).then(
@@ -391,7 +455,7 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
391
  keyTxt.change(set_key, [current_model, keyTxt], [user_api_key, status_display], api_name="set_key").then(**get_usage_args)
392
  keyTxt.submit(**get_usage_args)
393
  single_turn_checkbox.change(set_single_turn, [current_model, single_turn_checkbox], None)
394
- model_select_dropdown.change(get_model, [model_select_dropdown, lora_select_dropdown, user_api_key, temperature_slider, top_p_slider, systemPromptTxt, user_name], [current_model, status_display, chatbot, lora_select_dropdown], show_progress=True, api_name="get_model")
395
  model_select_dropdown.change(toggle_like_btn_visibility, [model_select_dropdown], [like_dislike_area], show_progress=False)
396
  lora_select_dropdown.change(get_model, [model_select_dropdown, lora_select_dropdown, user_api_key, temperature_slider, top_p_slider, systemPromptTxt, user_name], [current_model, status_display, chatbot], show_progress=True)
397
 
@@ -425,10 +489,23 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
425
  downloadFile,
426
  show_progress=True,
427
  )
428
- historyRefreshBtn.click(get_history_names, [gr.State(False), user_name], [historyFileSelectDropdown])
 
429
  historyFileSelectDropdown.change(**load_history_from_file_args)
430
  downloadFile.change(upload_chat_history, [current_model, downloadFile, user_name], [saveFileName, systemPromptTxt, chatbot])
431
 
 
 
 
 
 
 
 
 
 
 
 
 
432
  # Advanced
433
  max_context_length_slider.change(set_token_upper_limit, [current_model, max_context_length_slider], None)
434
  temperature_slider.change(set_temperature, [current_model, temperature_slider], None)
@@ -444,15 +521,24 @@ with gr.Blocks(css=customCSS, theme=small_and_beautiful_theme) as demo:
444
  default_btn.click(
445
  reset_default, [], [apihostTxt, proxyTxt, status_display], show_progress=True
446
  )
447
- changeAPIURLBtn.click(
448
- change_api_host,
449
- [apihostTxt],
450
- [status_display],
451
- show_progress=True,
452
- )
453
- changeProxyBtn.click(
454
- change_proxy,
455
- [proxyTxt],
 
 
 
 
 
 
 
 
 
456
  [status_display],
457
  show_progress=True,
458
  )
@@ -469,5 +555,5 @@ if __name__ == "__main__":
469
  reload_javascript()
470
  demo.queue(concurrency_count=CONCURRENT_COUNT).launch(
471
  blocked_paths=["config.json"],
472
- favicon_path="./assets/favicon.ico"
473
  )
1
  # -*- coding:utf-8 -*-
 
2
  import logging
3
+ logging.basicConfig(
4
+ level=logging.INFO,
5
+ format="%(asctime)s [%(levelname)s] [%(filename)s:%(lineno)d] %(message)s",
6
+ )
7
 
8
+ import colorama
9
  import gradio as gr
10
 
11
  from modules import config
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)
23
  gr.Chatbot._postprocess_chat_messages = postprocess_chat_messages
24
  gr.Chatbot.postprocess = postprocess
25
 
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 = MODELS[DEFAULT_MODEL], access_key = my_api_key)[0]
31
 
32
+ with gr.Blocks(theme=small_and_beautiful_theme) as demo:
33
  user_name = gr.State("")
34
  promptTemplates = gr.State(load_template(get_template_names(plain=True)[0], mode=2))
35
  user_question = gr.State("")
40
  topic = gr.State(i18n("未命名对话历史记录"))
41
 
42
  with gr.Row():
43
+ gr.HTML(CHUANHU_TITLE, elem_id="app-title")
44
+ status_display = gr.Markdown(get_geoip(), elem_id="status-display")
45
+ with gr.Row(elem_id="float-display"):
46
+ user_info = gr.Markdown(value="getting user info...", elem_id="user-info")
47
+ config_info = gr.HTML(get_html("config_info.html").format(bot_avatar=config.bot_avatar, user_avatar=config.user_avatar), visible=False, elem_id="config-info")
48
+ update_info = gr.HTML(get_html("update.html").format(
49
+ current_version=repo_tag_html(),
50
+ version_time=version_time(),
51
+ cancel_btn=i18n("取消"),
52
+ update_btn=i18n("更新"),
53
+ seenew_btn=i18n("详情"),
54
+ ok_btn=i18n("好"),
55
+ ), visible=check_update)
56
+
57
+ with gr.Row(equal_height=True):
58
  with gr.Column(scale=5):
59
  with gr.Row():
60
+ chatbot = gr.Chatbot(label="Chuanhu Chat", elem_id="chuanhu-chatbot", latex_delimiters=latex_delimiters_set, height=700)
61
  with gr.Row():
62
  with gr.Column(min_width=225, scale=12):
63
  user_input = gr.Textbox(
64
+ elem_id="user-input-tb",
65
+ show_label=False, placeholder=i18n("在这里输入"),
66
+ container=False
67
+ )
68
  with gr.Column(min_width=42, scale=1):
69
+ submitBtn = gr.Button(value="", variant="primary", elem_id="submit-btn")
70
+ cancelBtn = gr.Button(value="", variant="secondary", visible=False, elem_id="cancel-btn")
71
+ with gr.Row(elem_id="chatbot-buttons"):
72
+ with gr.Column(min_width=120, scale=1):
73
+ emptyBtn = gr.Button(
74
+ i18n("🧹 新的对话"), elem_id="empty-btn"
75
+ )
76
+ with gr.Column(min_width=120, scale=1):
77
+ retryBtn = gr.Button(i18n("🔄 重新生成"))
78
+ with gr.Column(min_width=120, scale=1):
79
+ delFirstBtn = gr.Button(i18n("🗑️ 删除最旧对话"))
80
+ with gr.Column(min_width=120, scale=1):
81
+ delLastBtn = gr.Button(i18n("🗑️ 删除最新对话"))
82
  with gr.Row(visible=False) as like_dislike_area:
83
  with gr.Column(min_width=20, scale=1):
84
  likeBtn = gr.Button(i18n("👍"))
97
  label="API-Key",
98
  )
99
  if multi_api_key:
100
+ usageTxt = gr.Markdown(i18n("多账号模式已开启,无需输入key,可直接开始对话"), elem_id="usage-display", elem_classes="insert-block", visible=show_api_billing)
101
  else:
102
+ usageTxt = gr.Markdown(i18n("**发送消息** 或 **提交key** 以显示额度"), elem_id="usage-display", elem_classes="insert-block", visible=show_api_billing)
103
  model_select_dropdown = gr.Dropdown(
104
  label=i18n("选择模型"), choices=MODELS, multiselect=False, value=MODELS[DEFAULT_MODEL], interactive=True
105
  )
107
  label=i18n("选择LoRA模型"), choices=[], multiselect=False, interactive=True, visible=False
108
  )
109
  with gr.Row():
110
+ single_turn_checkbox = gr.Checkbox(label=i18n("单轮对话"), value=False, elem_classes="switch-checkbox")
111
+ use_websearch_checkbox = gr.Checkbox(label=i18n("使用在线搜索"), value=False, elem_classes="switch-checkbox")
112
  language_select_dropdown = gr.Dropdown(
113
  label=i18n("选择回复语言(针对搜索&索引功能)"),
114
  choices=REPLY_LANGUAGES,
115
  multiselect=False,
116
  value=REPLY_LANGUAGES[0],
117
  )
118
+ index_files = gr.Files(label=i18n("上传"), type="file", elem_id="upload-index-file")
119
  two_column = gr.Checkbox(label=i18n("双栏pdf"), value=advance_docs["pdf"].get("two_column", False))
120
  summarize_btn = gr.Button(i18n("总结"))
121
  # TODO: 公式ocr
127
  placeholder=i18n("在这里输入System Prompt..."),
128
  label="System prompt",
129
  value=INITIAL_SYSTEM_PROMPT,
130
+ lines=10
131
+ )
132
  with gr.Accordion(label=i18n("加载Prompt模板"), open=True):
133
  with gr.Column():
134
  with gr.Row():
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():
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):
161
  historyFileSelectDropdown = gr.Dropdown(
162
  label=i18n("从列表中加载对话"),
163
  choices=get_history_names(plain=True),
164
+ multiselect=False,
165
+ container=False,
166
  )
167
+ with gr.Row():
168
+ with gr.Column(min_width=42, scale=1):
169
+ historyRefreshBtn = gr.Button(i18n("🔄 刷新"))
170
+ with gr.Column(min_width=42, scale=1):
171
+ historyDeleteBtn = gr.Button(i18n("🗑️ 删除"))
172
  with gr.Row():
173
  with gr.Column(scale=6):
174
  saveFileName = gr.Textbox(
176
  placeholder=i18n("设置文件名: 默认为.json,可选为.md"),
177
  label=i18n("设置保存文件名"),
178
  value=i18n("对话历史记录"),
179
+ elem_classes="no-container"
180
+ # container=False,
181
+ )
182
  with gr.Column(scale=1):
183
  saveHistoryBtn = gr.Button(i18n("💾 保存对话"))
184
  exportMarkdownBtn = gr.Button(i18n("📝 导出为Markdown"))
187
  with gr.Column():
188
  downloadFile = gr.File(interactive=True)
189
 
190
+ with gr.Tab(label=i18n("微调")):
191
+ openai_train_status = gr.Markdown(label=i18n("训练状态"), value=i18n("在这里[查看使用介绍](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B#%E5%BE%AE%E8%B0%83-gpt-35)"))
192
+
193
+ with gr.Tab(label=i18n("准备数据集")):
194
+ dataset_preview_json = gr.JSON(label=i18n("数据集预览"), readonly=True)
195
+ dataset_selection = gr.Files(label = i18n("选择数据集"), file_types=[".xlsx", ".jsonl"], file_count="single")
196
+ upload_to_openai_btn = gr.Button(i18n("上传到OpenAI"), variant="primary", interactive=False)
197
+
198
+ with gr.Tab(label=i18n("训练")):
199
+ openai_ft_file_id = gr.Textbox(label=i18n("文件ID"), value="", lines=1, placeholder=i18n("上传到 OpenAI 后自动填充"))
200
+ openai_ft_suffix = gr.Textbox(label=i18n("模型名称后缀"), value="", lines=1, placeholder=i18n("可选,用于区分不同的模型"))
201
+ openai_train_epoch_slider = gr.Slider(label=i18n("训练轮数(Epochs)"), minimum=1, maximum=100, value=3, step=1, interactive=True)
202
+ openai_start_train_btn = gr.Button(i18n("开始训练"), variant="primary", interactive=False)
203
+
204
+ with gr.Tab(label=i18n("状态")):
205
+ openai_status_refresh_btn = gr.Button(i18n("刷新状态"))
206
+ openai_cancel_all_jobs_btn = gr.Button(i18n("取消所有任务"))
207
+ add_to_models_btn = gr.Button(i18n("添加训练好的模型到模型列表"), interactive=False)
208
+
209
  with gr.Tab(label=i18n("高级")):
210
+ gr.HTML(get_html("appearance_switcher.html").format(label=i18n("切换亮暗色主题")), elem_classes="insert-block")
 
211
  use_streaming_checkbox = gr.Checkbox(
212
+ label=i18n("实时传输回答"), value=True, visible=ENABLE_STREAMING_OPTION, elem_classes="switch-checkbox"
213
  )
214
+ checkUpdateBtn = gr.Button(i18n("🔄 检查更新..."), visible=check_update)
215
+ gr.Markdown(i18n("# ⚠️ 务必谨慎更改 ⚠️"), elem_id="advanced-warning")
216
  with gr.Accordion(i18n("参数"), open=False):
217
  temperature_slider = gr.Slider(
218
  minimum=-0,
240
  )
241
  stop_sequence_txt = gr.Textbox(
242
  show_label=True,
243
+ placeholder=i18n("停止符,用英文逗号隔开..."),
244
  label="stop",
245
  value="",
246
  lines=1,
292
  lines=1,
293
  )
294
 
295
+ with gr.Accordion(i18n("网络参数"), open=False):
296
+ gr.Markdown(i18n("---\n⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置"), elem_id="netsetting-warning")
297
+ default_btn = gr.Button(i18n("🔙 恢复默认网络设置"))
298
+ # 网络代理
299
+ proxyTxt = gr.Textbox(
300
+ show_label=True,
301
+ placeholder=i18n("未设置代理..."),
302
+ label=i18n("代理地址"),
303
+ value=config.http_proxy,
304
+ lines=1,
305
+ interactive=False,
306
+ # container=False,
307
+ elem_classes="view-only-textbox no-container",
308
+ )
309
+ # changeProxyBtn = gr.Button(i18n("🔄 设置代理地址"))
310
+
311
  # 优先展示自定义的api_host
312
  apihostTxt = gr.Textbox(
313
  show_label=True,
314
+ placeholder="api.openai.com",
315
+ label="OpenAI API-Host",
316
  value=config.api_host or shared.API_HOST,
317
  lines=1,
318
+ interactive=False,
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
  gr.Markdown(CHUANHU_DESCRIPTION, elem_id="description")
327
  gr.HTML(get_html("footer.html").format(versions=versions_html()), elem_id="footer")
382
  outputs=[saveFileName, systemPromptTxt, chatbot]
383
  )
384
 
385
+ refresh_history_args = dict(
386
+ fn=get_history_names, inputs=[gr.State(False), user_name], outputs=[historyFileSelectDropdown]
387
+ )
388
+
389
 
390
  # Chatbot
391
  cancelBtn.click(interrupt, [current_model], [])
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(
455
  keyTxt.change(set_key, [current_model, keyTxt], [user_api_key, status_display], api_name="set_key").then(**get_usage_args)
456
  keyTxt.submit(**get_usage_args)
457
  single_turn_checkbox.change(set_single_turn, [current_model, single_turn_checkbox], None)
458
+ model_select_dropdown.change(get_model, [model_select_dropdown, lora_select_dropdown, user_api_key, temperature_slider, top_p_slider, systemPromptTxt, user_name], [current_model, status_display, chatbot, lora_select_dropdown, user_api_key, keyTxt], show_progress=True, api_name="get_model")
459
  model_select_dropdown.change(toggle_like_btn_visibility, [model_select_dropdown], [like_dislike_area], show_progress=False)
460
  lora_select_dropdown.change(get_model, [model_select_dropdown, lora_select_dropdown, user_api_key, temperature_slider, top_p_slider, systemPromptTxt, user_name], [current_model, status_display, chatbot], show_progress=True)
461
 
489
  downloadFile,
490
  show_progress=True,
491
  )
492
+ historyRefreshBtn.click(**refresh_history_args)
493
+ historyDeleteBtn.click(delete_chat_history, [current_model, historyFileSelectDropdown, user_name], [status_display, historyFileSelectDropdown, chatbot], _js='(a,b,c)=>{return showConfirmationDialog(a, b, c);}')
494
  historyFileSelectDropdown.change(**load_history_from_file_args)
495
  downloadFile.change(upload_chat_history, [current_model, downloadFile, user_name], [saveFileName, systemPromptTxt, chatbot])
496
 
497
+ # Train
498
+ dataset_selection.upload(handle_dataset_selection, dataset_selection, [dataset_preview_json, upload_to_openai_btn, openai_train_status])
499
+ dataset_selection.clear(handle_dataset_clear, [], [dataset_preview_json, upload_to_openai_btn])
500
+ upload_to_openai_btn.click(upload_to_openai, [dataset_selection], [openai_ft_file_id, openai_train_status], show_progress=True)
501
+
502
+ openai_ft_file_id.change(lambda x: gr.update(interactive=True) if len(x) > 0 else gr.update(interactive=False), [openai_ft_file_id], [openai_start_train_btn])
503
+ openai_start_train_btn.click(start_training, [openai_ft_file_id, openai_ft_suffix, openai_train_epoch_slider], [openai_train_status])
504
+
505
+ openai_status_refresh_btn.click(get_training_status, [], [openai_train_status, add_to_models_btn])
506
+ add_to_models_btn.click(add_to_models, [], [model_select_dropdown, openai_train_status], show_progress=True)
507
+ openai_cancel_all_jobs_btn.click(cancel_all_jobs, [], [openai_train_status], show_progress=True)
508
+
509
  # Advanced
510
  max_context_length_slider.change(set_token_upper_limit, [current_model, max_context_length_slider], None)
511
  temperature_slider.change(set_temperature, [current_model, temperature_slider], None)
521
  default_btn.click(
522
  reset_default, [], [apihostTxt, proxyTxt, status_display], show_progress=True
523
  )
524
+ # changeAPIURLBtn.click(
525
+ # change_api_host,
526
+ # [apihostTxt],
527
+ # [status_display],
528
+ # show_progress=True,
529
+ # )
530
+ # changeProxyBtn.click(
531
+ # change_proxy,
532
+ # [proxyTxt],
533
+ # [status_display],
534
+ # show_progress=True,
535
+ # )
536
+ checkUpdateBtn.click(fn=None, _js='manualCheckUpdate')
537
+
538
+ # Invisible elements
539
+ updateChuanhuBtn.click(
540
+ update_chuanhu,
541
+ [],
542
  [status_display],
543
  show_progress=True,
544
  )
555
  reload_javascript()
556
  demo.queue(concurrency_count=CONCURRENT_COUNT).launch(
557
  blocked_paths=["config.json"],
558
+ favicon_path="./web_assets/favicon.ico",
559
  )
Dockerfile CHANGED
@@ -1,15 +1,18 @@
1
- FROM python:3.9 as builder
2
- RUN apt-get update && apt-get install -y build-essential
 
 
 
3
  COPY requirements.txt .
4
  COPY requirements_advanced.txt .
5
- RUN pip install --user -r requirements.txt
6
- # RUN pip install --user -r requirements_advanced.txt
7
 
8
- FROM python:3.9
9
- MAINTAINER iskoldt
10
  COPY --from=builder /root/.local /root/.local
11
  ENV PATH=/root/.local/bin:$PATH
12
  COPY . /app
13
  WORKDIR /app
14
- ENV dockerrun yes
15
- CMD ["python3", "-u", "ChuanhuChatbot.py", "2>&1", "|", "tee", "/var/log/application.log"]
1
+ FROM python:3.9-slim-buster as builder
2
+ RUN apt-get update \
3
+ && apt-get install -y build-essential \
4
+ && apt-get clean \
5
+ && rm -rf /var/lib/apt/lists/*
6
  COPY requirements.txt .
7
  COPY requirements_advanced.txt .
8
+ RUN pip install --user --no-cache-dir -r requirements.txt
9
+ # RUN pip install --user --no-cache-dir -r requirements_advanced.txt
10
 
11
+ FROM python:3.9-slim-buster
12
+ LABEL maintainer="iskoldt"
13
  COPY --from=builder /root/.local /root/.local
14
  ENV PATH=/root/.local/bin:$PATH
15
  COPY . /app
16
  WORKDIR /app
17
+ ENV dockerrun=yes
18
+ CMD ["python3", "-u", "ChuanhuChatbot.py","2>&1", "|", "tee", "/var/log/application.log"]
config_example.json CHANGED
@@ -1,24 +1,60 @@
1
  {
2
- // 你的OpenAI API Key,一般必填,
3
- // 若缺省填为 "openai_api_key": "" 则必须再在图形界面中填入API Key
4
- "openai_api_key": "",
5
- // 你的xmchat API Key,与OpenAI API Key不同
6
- "xmchat_api_key": "",
7
- "language": "auto",
8
- // 如果使用代理,请取消注释下面的两行,并替换代理URL
9
- // "https_proxy": "http://127.0.0.1:1079",
10
- // "http_proxy": "http://127.0.0.1:1079",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  "users": [], // 用户列表,[[用户名1, 密码1], [用户名2, 密码2], ...]
12
  "local_embedding": false, //是否在本地编制索引
 
 
13
  "default_model": "gpt-3.5-turbo", // 默认模型
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  "advance_docs": {
15
  "pdf": {
16
- // 是否认为PDF是双栏的
17
- "two_column": false,
18
- // 是否使用OCR识别PDF中的公式
19
- "formula_ocr": true
20
  }
21
  },
 
 
22
  // 是否多个API Key轮换使用
23
  "multi_api_key": false,
24
  "api_key_list": [
@@ -26,7 +62,12 @@
26
  "sk-xxxxxxxxxxxxxxxxxxxxxxxx2",
27
  "sk-xxxxxxxxxxxxxxxxxxxxxxxx3"
28
  ],
29
- // 如果使用自定义端口、自定义ip,请取消注释并替换对应内容
 
 
 
 
 
30
  // "server_name": "0.0.0.0",
31
  // "server_port": 7860,
32
  // 如果要share到gradio,设置为true
1
  {
2
+ // 各配置具体说明,见 [https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#配置-configjson]
3
+
4
+ //== API 配置 ==
5
+ "openai_api_key": "", // 你的 OpenAI API Key,一般必填,若空缺则需在图形界面中填入API Key
6
+ "google_palm_api_key": "", // 你的 Google PaLM API Key,用于 Google PaLM 对话模型
7
+ "xmchat_api_key": "", // 你的 xmchat API Key,用于 XMChat 对话模型
8
+ "minimax_api_key": "", // 你的 MiniMax API Key,用于 MiniMax 对话模型
9
+ "minimax_group_id": "", // 你的 MiniMax Group ID,用于 MiniMax 对话模型
10
+ "midjourney_proxy_api_base": "https://xxx/mj", // 你的 https://github.com/novicezk/midjourney-proxy 代理地址
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 ==
17
+ "openai_api_type": "openai", // 可选项:azure, openai
18
+ "azure_openai_api_key": "", // 你的 Azure OpenAI API Key,用于 Azure OpenAI 对话模型
19
+ "azure_openai_api_base_url": "", // 你的 Azure Base URL
20
+ "azure_openai_api_version": "2023-05-15", // 你的 Azure OpenAI API 版本
21
+ "azure_deployment_name": "", // 你的 Azure OpenAI Chat 模型 Deployment 名称
22
+ "azure_embedding_deployment_name": "", // 你的 Azure OpenAI Embedding 模型 Deployment 名称
23
+ "azure_embedding_model_name": "text-embedding-ada-002", // 你的 Azure OpenAI Embedding 模型名称
24
+
25
+ //== 基础配置 ==
26
+ "language": "auto", // 界面语言,可选"auto", "zh-CN", "en-US", "ja-JP", "ko-KR", "sv-SE"
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
+ "bot_avatar": "default", // 机器人头像,可填写图片链接、Data URL (base64),或者"none"(不显示头像)
33
+ "user_avatar": "default", // 用户头像,可填写图片链接、Data URL (base64),或者"none"(不显示头像)
34
+
35
+ //== API 用量 ==
36
+ "show_api_billing": false, //是否显示OpenAI API用量(启用需要填写sensitive_id)
37
+ "sensitive_id": "", // 你 OpenAI 账户的 Sensitive ID,用于查询 API 用量
38
+ "usage_limit": 120, // 该 OpenAI API Key 的当月限额,单位:美元,用于计算百分比和显示上限
39
+ "legacy_api_usage": false, // 是否使用旧版 API 用量查询接口(OpenAI现已关闭该接口,但是如果你在使用第三方 API,第三方可能仍然支持此接口)
40
+
41
+ //== 川虎助理设置 ==
42
+ "default_chuanhu_assistant_model": "gpt-4", //川虎助理使用的模型,可选gpt-3.5-turbo或者gpt-4等
43
+ "GOOGLE_CSE_ID": "", //谷歌搜索引擎ID,用于川虎助理Pro模式,获取方式请看 https://stackoverflow.com/questions/37083058/programmatically-searching-google-in-python-using-custom-search
44
+ "GOOGLE_API_KEY": "", //谷歌API Key,用于川虎助理Pro模式
45
+ "WOLFRAM_ALPHA_APPID": "", //Wolfram Alpha API Key,用于川虎助理Pro模式,获取方式请看 https://products.wolframalpha.com/api/
46
+ "SERPAPI_API_KEY": "", //SerpAPI API Key,用于川虎助理Pro模式,获取方式请看 https://serpapi.com/
47
+
48
+ //== 文档处理与显示 ==
49
+ "latex_option": "default", // LaTeX 公式渲染策略,可选"default", "strict", "all"或者"disabled"
50
  "advance_docs": {
51
  "pdf": {
52
+ "two_column": false, // 是否认为PDF是双栏的
53
+ "formula_ocr": true // 是否使用OCR识别PDF中的公式
 
 
54
  }
55
  },
56
+
57
+ //== 高级配置 ==
58
  // 是否多个API Key轮换使用
59
  "multi_api_key": false,
60
  "api_key_list": [
62
  "sk-xxxxxxxxxxxxxxxxxxxxxxxx2",
63
  "sk-xxxxxxxxxxxxxxxxxxxxxxxx3"
64
  ],
65
+ // 自定义OpenAI API Base
66
+ // "openai_api_base": "https://api.openai.com",
67
+ // 自定��使用代理(请替换代理URL)
68
+ // "https_proxy": "http://127.0.0.1:1079",
69
+ // "http_proxy": "http://127.0.0.1:1079",
70
+ // 自定义端口、自定义ip(请替换对应内容)
71
  // "server_name": "0.0.0.0",
72
  // "server_port": 7860,
73
  // 如果要share到gradio,设置为true
locale/en_US.json CHANGED
@@ -32,24 +32,33 @@
32
  "📝 导出为Markdown": "📝 Export as Markdown",
33
  "默认保存于history文件夹": "Default save in history folder",
34
  "高级": "Advanced",
35
- "# ⚠️ 务必谨慎更改 ⚠️\n\n如果无法使用请恢复默认设置": "# ⚠️ Caution: Changes require care. ⚠️\n\nIf unable to use, restore default settings.",
36
  "参数": "Parameters",
37
- "在这里输入停止符,用英文逗号隔开...": "Type in stop token here, separated by comma...",
38
  "用于定位滥用行为": "Used to locate abuse",
39
  "用户名": "Username",
40
- "网络设置": "Network Settings",
41
  "在这里输入API-Host...": "Type in API-Host here...",
42
  "🔄 切换API地址": "🔄 Switch API Address",
43
- "在这里输入代理地址...": "Type in proxy address here...",
44
- "代理地址(示例:http://127.0.0.1:10809)": "Proxy address (example: http://127.0.0.1:10809)",
45
  "🔄 设置代理地址": "🔄 Set Proxy Address",
46
- "🔙 恢复默认设置": "🔙 Restore Default Settings",
 
 
 
 
 
 
 
47
  "川虎Chat 🚀": "Chuanhu Chat 🚀",
48
  "开始实时传输回答……": "Start streaming output...",
49
  "Token 计数: ": "Token Count: ",
50
- ",本次对话累计消耗了 ": "Total cost for this dialogue is ",
51
  "**获取API使用情况失败**": "**Failed to get API usage**",
 
 
52
  "**本月使用金额** ": "**Monthly usage** ",
 
53
  "获取API使用情况失败:": "Failed to get API usage:",
54
  "API密钥更改为了": "The API key is changed to",
55
  "JSON解析错误,收到的内容: ": "JSON parsing error, received content: ",
@@ -64,10 +73,15 @@
64
  "API key为空,请检查是否输入正确。": "API key is empty, check whether it is entered correctly.",
65
  "请输入对话内容。": "Enter the content of the conversation.",
66
  "账单信息不适用": "Billing information is not applicable",
67
- "由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)[明昭MZhao](https://space.bilibili.com/24807452)开发<br />访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "developor: Bilibili [土川虎虎虎](https://space.bilibili.com/29125536) and [明昭MZhao](https://space.bilibili.com/24807452)\n\nDownload latest code from [GitHub](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
68
  "切换亮暗色主题": "Switch light/dark theme",
69
  "您的IP区域:未知。": "Your IP region: Unknown.",
70
  "获取IP地理位置失败。原因:": "Failed to get IP location. Reason: ",
71
  "。你仍然可以使用聊天功能。": ". You can still use the chat function.",
72
- "您的IP区域:": "Your IP region: "
 
 
 
 
 
73
  }
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
  "🔄 设置代理地址": "🔄 Set Proxy Address",
45
+ "🔙 恢复默认网络设置": "🔙 Reset Network Settings",
46
+ "🔄 检查更新...": "🔄 Check for Update...",
47
+ "取消": "Cancel",
48
+ "更新": "Update",
49
+ "详情": "Details",
50
+ "好": "OK",
51
+ "更新成功,请重启本程序": "Updated successfully, please restart this program",
52
+ "更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "Update failed, please try [manually updating](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)",
53
  "川虎Chat 🚀": "Chuanhu Chat 🚀",
54
  "开始实时传输回答……": "Start streaming output...",
55
  "Token 计数: ": "Token Count: ",
56
+ ",本次对话累计消耗了 ": ", Total cost for this dialogue is ",
57
  "**获取API使用情况失败**": "**Failed to get API usage**",
58
+ "**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**Failed to get API usage**, correct sensitive_id needed in `config.json`",
59
+ "**获取API使用情况失败**,sensitive_id错误或已过期": "**Failed to get API usage**, wrong or expired sensitive_id",
60
  "**本月使用金额** ": "**Monthly usage** ",
61
+ "本月使用金额": "Monthly usage",
62
  "获取API使用情况失败:": "Failed to get API usage:",
63
  "API密钥更改为了": "The API key is changed to",
64
  "JSON解析错误,收到的内容: ": "JSON parsing error, received content: ",
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
+ "由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)",
77
  "切换亮暗色主题": "Switch light/dark theme",
78
  "您的IP区域:未知。": "Your IP region: Unknown.",
79
  "获取IP地理位置失败。原因:": "Failed to get IP location. Reason: ",
80
  "。你仍然可以使用聊天功能。": ". You can still use the chat function.",
81
+ "您的IP区域:": "Your IP region: ",
82
+ "总结": "Summarize",
83
+ "生成内容总结中……": "Generating content summary...",
84
+ "由于下面的原因,Google 拒绝返回 PaLM 的回答:\n\n": "Due to the following reasons, Google refuses to provide an answer to PaLM: \n\n",
85
+ "---\n⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "---\n⚠️ To ensure the security of API-Key, please modify the network settings in the configuration file `config.json`.",
86
+ "网络参数": "Network parameter"
87
  }
locale/ja_JP.json CHANGED
@@ -32,24 +32,33 @@
32
  "📝 导出为Markdown": "📝 Markdownでエクスポート",
33
  "默认保存于history文件夹": "デフォルトでhistoryフォルダに保存されます",
34
  "高级": "Advanced",
35
- "# ⚠️ 务必谨慎更改 ⚠️\n\n如果无法使用请恢复默认设置": "# ⚠️ 変更には慎重に ⚠️\n\nもし動作しない場合は、デフォルト設定に戻してください。",
36
  "参数": "パラメータ",
37
- "在这里输入停止符,用英文逗号隔开...": "ここにストップ文字を英語のカンマで区切って入力してください...",
38
  "用于定位滥用行为": "不正行為を特定するために使用されます",
39
  "用户名": "ユーザー名",
40
- "网络设置": "ネットワーク設定",
41
  "在这里输入API-Host...": "API-Hostを入力してください...",
42
  "🔄 切换API地址": "🔄 APIアドレスを切り替え",
43
- "在这里输入代理地址...": "プロキシアドレスを入力してください...",
44
- "代理地址(示例:http://127.0.0.1:10809)": "プロキシアドレス(例:http://127.0.0.1:10809)",
45
  "🔄 设置代理地址": "🔄 プロキシアドレスを設定",
46
- "🔙 恢复默认设置": "🔙 デフォルト設定に戻す",
 
 
 
 
 
 
 
47
  "川虎Chat 🚀": "川虎Chat 🚀",
48
  "开始实时传输回答……": "ストリーム出力開始……",
49
  "Token 计数: ": "Token数: ",
50
  ",本次对话累计消耗了 ": ", 今の会話で消費合計 ",
51
  "**获取API使用情况失败**": "**API使用状況の取得に失敗しました**",
 
 
52
  "**本月使用金额** ": "**今月の使用料金** ",
 
53
  "获取API使用情况失败:": "API使用状況の取得に失敗しました:",
54
  "API密钥更改为了": "APIキーが変更されました",
55
  "JSON解析错误,收到的内容: ": "JSON解析エラー、受信内容: ",
@@ -64,10 +73,15 @@
64
  "API key为空,请检查是否输入正确。": "APIキーが入力されていません。正しく入力されているか確認してください。",
65
  "请输入对话内容。": "会話内容を入力してください。",
66
  "账单信息不适用": "課金情報は対象外です",
67
- "由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)[明昭MZhao](https://space.bilibili.com/24807452)开发<br />访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "開発:Bilibili [土川虎虎虎](https://space.bilibili.com/29125536) と [明昭MZhao](https://space.bilibili.com/24807452)\n\n最新コードは川虎Chatのサイトへ [GitHubプロジェクト](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
68
  "切换亮暗色主题": "テーマの明暗切替",
69
  "您的IP区域:未知。": "あなたのIPアドレス地域:不明",
70
  "获取IP地理位置失败。原因:": "IPアドレス地域の取得に失敗しました。理由:",
71
  "。你仍然可以使用聊天功能。": "。あなたはまだチャット機能を使用できます。",
72
- "您的IP区域:": "あなたのIPアドレス地域:"
73
- }
 
 
 
 
 
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
+ "更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "更新に失敗しました、[手動での更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)をお試しください。",
53
  "川虎Chat 🚀": "川虎Chat 🚀",
54
  "开始实时传输回答……": "ストリーム出力開始……",
55
  "Token 计数: ": "Token数: ",
56
  ",本次对话累计消耗了 ": ", 今の会話で消費合計 ",
57
  "**获取API使用情况失败**": "**API使用状況の取得に失敗しました**",
58
+ "**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**API使用状況の取得に失敗しました**、`config.json`に正しい`sensitive_id`を入力する必要があります",
59
+ "**获取API使用情况失败**,sensitive_id错误或已过期": "**API使用状況の取得に失敗しました**、sensitive_idが間違っているか、期限切れです",
60
  "**本月使用金额** ": "**今月の使用料金** ",
61
+ "本月使用金额": "今月の使用料金",
62
  "获取API使用情况失败:": "API使用状況の取得に失敗しました:",
63
  "API密钥更改为了": "APIキーが変更されました",
64
  "JSON解析错误,收到的内容: ": "JSON解析エラー、受信内容: ",
73
  "API key为空,请检查是否输入正确。": "APIキーが入力されていません。正しく入力されているか確認してください。",
74
  "请输入对话内容。": "会話内容を入力してください。",
75
  "账单信息不适用": "課金情報は対象外です",
76
+ "由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)[明昭MZhao](https://space.bilibili.com/24807452) 和 [Keldos](https://github.com/Keldos-Li) 开发<br />访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "開発:Bilibili [土川虎虎虎](https://space.bilibili.com/29125536) と [明昭MZhao](https://space.bilibili.com/24807452) と [Keldos](https://github.com/Keldos-Li)\n\n最新コードは川虎Chatのサイトへ [GitHubプロジェクト](https://github.com/GaiZhenbiao/ChuanhuChatGPT)",
77
  "切换亮暗色主题": "テーマの明暗切替",
78
  "您的IP区域:未知。": "あなたのIPアドレス地域:不明",
79
  "获取IP地理位置失败。原因:": "IPアドレス地域の取得に失敗しました。理由:",
80
  "。你仍然可以使用聊天功能。": "。あなたはまだチャット機能を使用できます。",
81
+ "您的IP区域:": "あなたのIPアドレス地域:",
82
+ "总结": "要約する",
83
+ "生成内容总结中……": "コンテンツ概要を生成しています...",
84
+ "由于下面的原因,Google 拒绝返回 PaLM 的回答:\n\n": "Googleは以下の理由から、PaLMの回答を返すことを拒否しています:\n\n",
85
+ "---\n⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "---\n⚠️ APIキーの安全性を確保するために、`config.json`ファイルでネットワーク設定を変更してください。",
86
+ "网络参数": "ネットワークパラメータ"
87
+ }
locale/ko_KR.json ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "未命名对话历史记录": "이름없는 대화 기록",
3
+ "在这里输入": "여기에 입력하세요",
4
+ "🧹 新的对话": "🧹 새로운 대화",
5
+ "🔄 重新生成": "🔄 재생성",
6
+ "🗑️ 删除最旧对话": "🗑️ 가장 오래된 대화 삭제",
7
+ "🗑️ 删除最新对话": "🗑️ 최신 대화 삭제",
8
+ "🗑️ 删除": "🗑️ 삭제",
9
+ "模型": "LLM 모델",
10
+ "多账号模式已开启,无需输入key,可直接开始对话": "다중 계정 모드가 활성화되어 있으므로 키를 입력할 필요가 없이 바로 대화를 시작할 수 있습니다",
11
+ "**发送消息** 或 **提交key** 以显示额度": "**메세지를 전송** 하거나 **Key를 입력**하여 크레딧 표시",
12
+ "选择模型": "모델 선택",
13
+ "选择LoRA模型": "LoRA 모델 선택",
14
+ "实时传输回答": "실시간 전송",
15
+ "单轮对话": "단일 대화",
16
+ "使用在线搜索": "온라인 검색 사용",
17
+ "选择回复语言(针对搜索&索引功能)": "답장 언어 선택 (검색 & 인덱스용)",
18
+ "上传索引文件": "업로드",
19
+ "双栏pdf": "2-column pdf",
20
+ "识别公式": "formula OCR",
21
+ "在这里输入System Prompt...": "여기에 시스템 프롬프트를 입력하세요...",
22
+ "加载Prompt模板": "프롬프트 템플릿 불러오기",
23
+ "选择Prompt模板集合文件": "프롬프트 콜렉션 파일 선택",
24
+ "🔄 刷新": "🔄 새로고침",
25
+ "从Prompt模板中加载": "프롬프트 템플릿에서 불러오기",
26
+ "保存/加载": "저장/불러오기",
27
+ "保存/加载对话历史记录": "대화 기록 저장/불러오기",
28
+ "从列表中加载对话": "리스트에서 대화 불러오기",
29
+ "设置文件名: 默认为.json,可选为.md": "파일 이름 설정: 기본값: .json, 선택: .md",
30
+ "设置保存文件名": "저장 파일명 설정",
31
+ "对话历史记录": "대화 기록",
32
+ "💾 保存对话": "💾 대화 저장",
33
+ "📝 导出为Markdown": "📝 마크다운으로 내보내기",
34
+ "默认保存于history文件夹": "히스토리 폴더에 기본 저장",
35
+ "高级": "고급",
36
+ "# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ 주의: 변경시 주의하세요. ⚠️",
37
+ "参数": "파라미터들",
38
+ "停止符,用英文逗号隔开...": "여기에 정지 토큰 입력, ','로 구분됨...",
39
+ "用于定位滥用行为": "악용 사례 파악에 활용됨",
40
+ "用户名": "사용자 이름",
41
+ "在这里输入API-Host...": "여기에 API host를 입력하세요...",
42
+ "🔄 切换API地址": "🔄 API 주소 변경",
43
+ "未设置代理...": "대리인이 설정되지 않았습니다...",
44
+ "代理地址": "프록시 주소",
45
+ "🔄 设置代理地址": "🔄 프록시 주소 설정",
46
+ "🔙 恢复默认网络设置": "🔙 네트워크 설정 초기화",
47
+ "🔄 检查更新...": "🔄 업데이트 확인...",
48
+ "取消": "취소",
49
+ "更新": "업데이트",
50
+ "详情": "상세",
51
+ "好": "예",
52
+ "更新成功,请重启本程序": "업데이트 성공, 이 프로그램을 재시작 해주세요",
53
+ "更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "업데이트 실패, [수동 업데이트](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)를 시도하십시오",
54
+ "川虎Chat 🚀": "Chuanhu Chat 🚀",
55
+ "开始实时传输回答……": "실시간 응답 출력 시작...",
56
+ "Token 计数: ": "토큰 수: ",
57
+ ",本次对话累计消耗了 ": ",이 대화의 전체 비용은 ",
58
+ "**获取API使用情况失败**": "**API 사용량 가져오기 실패**",
59
+ "**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**API 사용량 가져오기 실패**. `config.json`에 올바른 `sensitive_id`를 입력해야 합니다",
60
+ "**获取API使用情况失败**,sensitive_id错误或已过期": "**API 사용량 가져오기 실패**. sensitive_id가 잘못되었거나 만료되었습니다",
61
+ "**本月使用金额** ": "**이번 달 사용금액** ",
62
+ "本月使用金额": "이번 달 사용금액",
63
+ "获取API使用情况失败:": "API 사용량 가져오기 실패:",
64
+ "API密钥更改为了": "API 키가 변경되었습니다.",
65
+ "JSON解析错误,收到的内容: ": "JSON 파싱 에러, 응답: ",
66
+ "模型设置为了:": "설정된 모델: ",
67
+ "☹️发生了错误:": "☹️에러: ",
68
+ "获取对话时发生错误,请查看后台日志": "대화를 가져오는 중 에러가 발생했습니다. 백그라운드 로그를 확인하세요",
69
+ "请检查网络连接,或者API-Key是否有效。": "네트워크 연결 또는 API키가 유효한지 확인하세요",
70
+ "连接超时,无法获取对话。": "연결 시간 초과, 대화를 가져올 수 없습니다.",
71
+ "读取超时,无法获取对话。": "읽기 시간 초과, 대화를 가져올 수 없습니다.",
72
+ "代理错误,无法获取对话。": "프록시 에러, 대화를 가져올 수 없습니다.",
73
+ "SSL错误,无法获取对话。": "SSL 에러, 대화를 가져올 수 없습니다.",
74
+ "API key为空,请检查是否输入正确。": "API 키가 비어 있습니다. 올바르게 입력되었는지 확인하십세요.",
75
+ "请输入对话内容。": "대화 내용을 입력하세요.",
76
+ "账单信息不适用": "청구 정보를 가져올 수 없습니다",
77
+ "由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)",
78
+ "切换亮暗色主题": "라이트/다크 테마 전환",
79
+ "您的IP区域:未知。": "IP 지역: 알 수 없음.",
80
+ "获取IP地理位置失败。原因:": "다음과 같은 이유로 IP 위치를 가져올 수 없습니다. 이유: ",
81
+ "。你仍然可以使用聊天功能。": ". 채팅 기능을 계속 사용할 수 있습니다.",
82
+ "您的IP区域:": "당신의 IP 지역: ",
83
+ "总结": "요약",
84
+ "生成内容总结中……": "콘텐츠 요약 생성중...",
85
+ "上传": "업로드",
86
+ "由于下面的原因,Google 拒绝返回 PaLM 的回答:\n\n": "구글은 다음과 같은 이유로 인해 PaLM의 응답을 거부합니다: \n\n",
87
+ "---\n⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "---\n⚠️ API-Key의 안전을 보장하기 위해 네트워크 설정을 `config.json` 구성 파일에서 수정해주세요.",
88
+ "网络参数": "네트워크 매개변수"
89
+ }
locale/sv-SE.json ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "未命名对话历史记录": "Onämnd Dialoghistorik",
3
+ "在这里输入": "Skriv in här",
4
+ "🧹 新的对话": "🧹 Ny Dialog",
5
+ "🔄 重新生成": "🔄 Regenerera",
6
+ "🗑️ 删除最旧对话": "🗑️ Ta bort äldsta dialogen",
7
+ "🗑️ 删除最新对话": "🗑️ Ta bort senaste dialogen",
8
+ "模型": "Modell",
9
+ "多账号模式已开启,无需输入key,可直接开始对话": "Flerkontoläge är aktiverat, ingen nyckel behövs, du kan starta dialogen direkt",
10
+ "**发送消息** 或 **提交key** 以显示额度": "**Skicka meddelande** eller **Skicka in nyckel** för att visa kredit",
11
+ "选择模型": "Välj Modell",
12
+ "选择LoRA模型": "Välj LoRA Modell",
13
+ "实时传输回答": "Strömmande utdata",
14
+ "单轮对话": "Enkel dialog",
15
+ "使用在线搜索": "Använd online-sökning",
16
+ "选择回复语言(针对搜索&索引功能)": "Välj svarspråk (för sök- och indexfunktion)",
17
+ "上传索引文件": "Ladda upp",
18
+ "双栏pdf": "Två-kolumns pdf",
19
+ "识别公式": "Formel OCR",
20
+ "在这里输入System Prompt...": "Skriv in System Prompt här...",
21
+ "加载Prompt模板": "Ladda Prompt-mall",
22
+ "选择Prompt模板集合文件": "Välj Prompt-mall Samlingsfil",
23
+ "🔄 刷新": "🔄 Uppdatera",
24
+ "从Prompt模板中加载": "Ladda från Prompt-mall",
25
+ "保存/加载": "Spara/Ladda",
26
+ "保存/加载对话历史记录": "Spara/Ladda Dialoghistorik",
27
+ "从列表中加载对话": "Ladda dialog från lista",
28
+ "设置文件名: 默认为.json,可选为.md": "Ställ in filnamn: standard är .json, valfritt är .md",
29
+ "设置保存文件名": "Ställ in sparfilnamn",
30
+ "对话历史记录": "Dialoghistorik",
31
+ "💾 保存对话": "💾 Spara Dialog",
32
+ "📝 导出为Markdown": "📝 Exportera som Markdown",
33
+ "默认保存于history文件夹": "Sparas som standard i mappen history",
34
+ "高级": "Avancerat",
35
+ "# ⚠️ 务必谨慎更改 ⚠️": "# ⚠️ Var försiktig med ändringar. ⚠️",
36
+ "参数": "Parametrar",
37
+ "停止符,用英文逗号隔开...": "Skriv in stopptecken här, separerade med kommatecken...",
38
+ "用于定位滥用行为": "Används för att lokalisera missbruk",
39
+ "用户名": "Användarnamn",
40
+ "在这里输入API-Host...": "Skriv in API-Host här...",
41
+ "🔄 切换API地址": "🔄 Byt API-adress",
42
+ "未设置代理...": "Inte inställd proxy...",
43
+ "代理地址": "Proxyadress",
44
+ "🔄 设置代理地址": "🔄 Ställ in Proxyadress",
45
+ "🔙 恢复网络默认设置": "🔙 Återställ Nätverksinställningar",
46
+ "🔄 检查更新...": "🔄 Sök efter uppdateringar...",
47
+ "取消": "Avbryt",
48
+ "更新": "Uppdatera",
49
+ "详情": "Detaljer",
50
+ "好": "OK",
51
+ "更新成功,请重启本程序": "Uppdaterat framgångsrikt, starta om programmet",
52
+ "更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)": "Uppdateringen misslyckades, prova att [uppdatera manuellt](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)",
53
+ "川虎Chat 🚀": "Chuanhu Chat 🚀",
54
+ "开始实时传输回答……": "Börjar strömma utdata...",
55
+ "Token 计数: ": "Tokenräkning: ",
56
+ ",本次对话累计消耗了 ": ", Total kostnad för denna dialog är ",
57
+ "**获取API使用情况失败**": "**Misslyckades med att hämta API-användning**",
58
+ "**获取API使用情况失败**,需在填写`config.json`中正确填写sensitive_id": "**Misslyckades med att hämta API-användning**, korrekt sensitive_id behövs i `config.json`",
59
+ "**获取API使用情况失败**,sensitive_id错误或已过期": "**Misslyckades med att hämta API-användning**, felaktig eller utgången sensitive_id",
60
+ "**本月使用金额** ": "**Månadens användning** ",
61
+ "本月使用金额": "Månadens användning",
62
+ "获取API使用情况失败:": "Misslyckades med att hämta API-användning:",
63
+ "API密钥更改为了": "API-nyckeln har ändrats till",
64
+ "JSON解析错误,收到的内容: ": "JSON-tolkningsfel, mottaget innehåll: ",
65
+ "模型设置为了:": "Modellen är inställd på: ",
66
+ "☹️发生了错误:": "☹️Fel: ",
67
+ "获取对话时发生错误,请查看后台日志": "Ett fel uppstod när dialogen hämtades, kontrollera bakgrundsloggen",
68
+ "请检查网络连接,或者API-Key是否有效。": "Kontrollera nätverksanslutningen eller om API-nyckeln är giltig.",
69
+ "连接超时,无法获取对话。": "Anslutningen tog för lång tid, kunde inte hämta dialogen.",
70
+ "读取超时,无法获取对话。": "Läsningen tog för lång tid, kunde inte hämta dialogen.",
71
+ "代理错误,无法获取对话。": "Proxyfel, kunde inte hämta dialogen.",
72
+ "SSL错误,无法获取对话。": "SSL-fel, kunde inte hämta dialogen.",
73
+ "API key为空,请检查是否输入正确。": "API-nyckeln är tom, kontrollera om den är korrekt inmatad.",
74
+ "请输入对话内容。": "Ange dialoginnehåll.",
75
+ "账单信息不适用": "Faktureringsinformation är inte tillämplig",
76
+ "由Bilibili [土川虎虎虎](https://space.bilibili.com/29125536)、[明昭MZhao](https://space.bilibili.com/24807452) 和 [Keldos](https://github.com/Keldos-Li) 开发<br />访问川虎Chat的 [GitHub项目](https://github.com/GaiZhenbiao/ChuanhuChatGPT) 下载最新版脚本": "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)",
77
+ "切换亮暗色主题": "Byt ljus/mörk tema",
78
+ "您的IP区域:未知。": "Din IP-region: Okänd.",
79
+ "获取IP地理位置失败。原因:": "Misslyckades med att hämta IP-plats. Orsak: ",
80
+ "。你仍然可以使用聊天功能。": ". Du kan fortfarande använda chattfunktionen.",
81
+ "您的IP区域:": "Din IP-region: ",
82
+ "总结": "Sammanfatta",
83
+ "生成内容总结中……": "Genererar innehållssammanfattning...",
84
+ "由于下面的原因,Google 拒绝返回 PaLM 的回答:\n\n": "På grund av följande skäl vägrar Google att ge ett svar till PaLM: \n\n",
85
+ "---\n⚠️ 为保证API-Key安全,请在配置文件`config.json`中修改网络设置": "---\n⚠️ För att säkerställa säkerheten för API-nyckeln, vänligen ändra nätverksinställningarna i konfigurationsfilen `config.json`.",
86
+ "网络参数": "nätverksparametrar"
87
+ }
modules/.DS_Store ADDED
Binary file (6.15 kB). View file
modules/__pycache__/config.cpython-311.pyc CHANGED
Binary files a/modules/__pycache__/config.cpython-311.pyc and b/modules/__pycache__/config.cpython-311.pyc differ
modules/__pycache__/config.cpython-39.pyc CHANGED
Binary files a/modules/__pycache__/config.cpython-39.pyc and b/modules/__pycache__/config.cpython-39.pyc differ
modules/__pycache__/index_func.cpython-311.pyc CHANGED
Binary files a/modules/__pycache__/index_func.cpython-311.pyc and b/modules/__pycache__/index_func.cpython-311.pyc differ
modules/__pycache__/index_func.cpython-39.pyc CHANGED
Binary files a/modules/__pycache__/index_func.cpython-39.pyc and b/modules/__pycache__/index_func.cpython-39.pyc differ
modules/__pycache__/overwrites.cpython-311.pyc CHANGED
Binary files a/modules/__pycache__/overwrites.cpython-311.pyc and b/modules/__pycache__/overwrites.cpython-311.pyc differ
modules/__pycache__/overwrites.cpython-39.pyc CHANGED
Binary files a/modules/__pycache__/overwrites.cpython-39.pyc and b/modules/__pycache__/overwrites.cpython-39.pyc differ
modules/__pycache__/pdf_func.cpython-311.pyc CHANGED
Binary files a/modules/__pycache__/pdf_func.cpython-311.pyc and b/modules/__pycache__/pdf_func.cpython-311.pyc differ
modules/__pycache__/presets.cpython-311.pyc CHANGED
Binary files a/modules/__pycache__/presets.cpython-311.pyc and b/modules/__pycache__/presets.cpython-311.pyc differ
modules/__pycache__/presets.cpython-39.pyc CHANGED
Binary files a/modules/__pycache__/presets.cpython-39.pyc and b/modules/__pycache__/presets.cpython-39.pyc differ
modules/__pycache__/repo.cpython-311.pyc ADDED
Binary file (14.1 kB). View file
modules/__pycache__/shared.cpython-311.pyc CHANGED
Binary files a/modules/__pycache__/shared.cpython-311.pyc and b/modules/__pycache__/shared.cpython-311.pyc differ
modules/__pycache__/shared.cpython-39.pyc CHANGED
Binary files a/modules/__pycache__/shared.cpython-39.pyc and b/modules/__pycache__/shared.cpython-39.pyc differ
modules/__pycache__/train_func.cpython-311.pyc ADDED
Binary file (11.7 kB). View file
modules/__pycache__/utils.cpython-311.pyc CHANGED
Binary files a/modules/__pycache__/utils.cpython-311.pyc and b/modules/__pycache__/utils.cpython-311.pyc differ
modules/__pycache__/utils.cpython-39.pyc CHANGED
Binary files a/modules/__pycache__/utils.cpython-39.pyc and b/modules/__pycache__/utils.cpython-39.pyc differ
modules/__pycache__/webui.cpython-311.pyc ADDED
Binary file (5.45 kB). View file
modules/config.py CHANGED
@@ -11,11 +11,11 @@ from . import presets
11
 
12
  __all__ = [
13
  "my_api_key",
 
14
  "authflag",
15
  "auth_list",
16
  "dockerflag",
17
  "retrieve_proxy",
18
- "log_level",
19
  "advance_docs",
20
  "update_doc_config",
21
  "usage_limit",
@@ -23,8 +23,11 @@ __all__ = [
23
  "server_name",
24
  "server_port",
25
  "share",
 
 
26
  "hide_history_when_not_logged_in",
27
- "default_chuanhu_assistant_model"
 
28
  ]
29
 
30
  # 添加一个统一的config文件,避免文件过多造成的疑惑(优先级最低)
@@ -35,10 +38,22 @@ if os.path.exists("config.json"):
35
  else:
36
  config = {}
37
 
 
 
 
 
 
 
 
 
38
  lang_config = config.get("language", "auto")
39
  language = os.environ.get("LANGUAGE", lang_config)
40
 
41
- hide_history_when_not_logged_in = config.get("hide_history_when_not_logged_in", False)
 
 
 
 
42
 
43
  if os.path.exists("api_key.txt"):
44
  logging.info("检测到api_key.txt文件,正在进行迁移...")
@@ -52,26 +67,44 @@ if os.path.exists("auth.json"):
52
  logging.info("检测到auth.json文件,正在进行迁移...")
53
  auth_list = []
54
  with open("auth.json", "r", encoding='utf-8') as f:
55
- auth = json.load(f)
56
- for _ in auth:
57
- if auth[_]["username"] and auth[_]["password"]:
58
- auth_list.append((auth[_]["username"], auth[_]["password"]))
59
- else:
60
- logging.error("请检查auth.json文件中的用户名和密码!")
61
- sys.exit(1)
62
  config["users"] = auth_list
63
  os.rename("auth.json", "auth(deprecated).json")
64
  with open("config.json", "w", encoding='utf-8') as f:
65
  json.dump(config, f, indent=4, ensure_ascii=False)
66
 
67
- ## 处理docker if we are running in Docker
68
  dockerflag = config.get("dockerflag", False)
69
  if os.environ.get("dockerrun") == "yes":
70
  dockerflag = True
71
 
72
- ## 处理 api-key 以及 允许的用户列表
73
  my_api_key = config.get("openai_api_key", "")
74
  my_api_key = os.environ.get("OPENAI_API_KEY", my_api_key)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
  xmchat_api_key = config.get("xmchat_api_key", "")
77
  os.environ["XMCHAT_API_KEY"] = xmchat_api_key
@@ -81,11 +114,23 @@ os.environ["MINIMAX_API_KEY"] = minimax_api_key
81
  minimax_group_id = config.get("minimax_group_id", "")
82
  os.environ["MINIMAX_GROUP_ID"] = minimax_group_id
83
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
  usage_limit = os.environ.get("USAGE_LIMIT", config.get("usage_limit", 120))
86
 
87
- ## 多账户机制
88
- multi_api_key = config.get("multi_api_key", False) # 是否开启多账户机制
89
  if multi_api_key:
90
  api_key_list = config.get("api_key_list", [])
91
  if len(api_key_list) == 0:
@@ -93,21 +138,26 @@ if multi_api_key:
93
  sys.exit(1)
94
  shared.state.set_api_key_queue(api_key_list)
95
 
96
- auth_list = config.get("users", []) # 实际上是使用者的列表
97
  authflag = len(auth_list) > 0 # 是否开启认证的状态值,改为判断auth_list长度
98
 
99
  # 处理自定义的api_host,优先读环境变量的配置,如果存在则自动装配
100
- api_host = os.environ.get("OPENAI_API_BASE", config.get("openai_api_base", None))
 
101
  if api_host is not None:
102
  shared.state.set_api_host(api_host)
 
 
103
 
104
- default_chuanhu_assistant_model = config.get("default_chuanhu_assistant_model", "gpt-3.5-turbo")
 
105
  for x in ["GOOGLE_CSE_ID", "GOOGLE_API_KEY", "WOLFRAM_ALPHA_APPID", "SERPAPI_API_KEY"]:
106
  if config.get(x, None) is not None:
107
  os.environ[x] = config[x]
108
 
 
109
  @contextmanager
110
- def retrieve_openai_api(api_key = None):
111
  old_api_key = os.environ.get("OPENAI_API_KEY", "")
112
  if api_key is None:
113
  os.environ["OPENAI_API_KEY"] = my_api_key
@@ -117,24 +167,20 @@ def retrieve_openai_api(api_key = None):
117
  yield api_key
118
  os.environ["OPENAI_API_KEY"] = old_api_key
119
 
120
- ## 处理log
121
- log_level = config.get("log_level", "INFO")
122
- logging.basicConfig(
123
- level=log_level,
124
- format="%(asctime)s [%(levelname)s] [%(filename)s:%(lineno)d] %(message)s",
125
- )
126
 
127
- ## 处理代理:
128
- http_proxy = config.get("http_proxy", "")
129
- https_proxy = config.get("https_proxy", "")
130
- http_proxy = os.environ.get("HTTP_PROXY", http_proxy)
131
- https_proxy = os.environ.get("HTTPS_PROXY", https_proxy)
 
132
 
133
  # 重置系统变量,在不需要设置的时候不设置环境变量,以免引起全局代理报错
134
  os.environ["HTTP_PROXY"] = ""
135
  os.environ["HTTPS_PROXY"] = ""
136
 
137
- local_embedding = config.get("local_embedding", False) # 是否使用本地embedding
 
138
 
139
  @contextmanager
140
  def retrieve_proxy(proxy=None):
@@ -151,22 +197,62 @@ def retrieve_proxy(proxy=None):
151
  old_var = os.environ["HTTP_PROXY"], os.environ["HTTPS_PROXY"]
152
  os.environ["HTTP_PROXY"] = http_proxy
153
  os.environ["HTTPS_PROXY"] = https_proxy
154
- yield http_proxy, https_proxy # return new proxy
155
 
156
  # return old proxy
157
  os.environ["HTTP_PROXY"], os.environ["HTTPS_PROXY"] = old_var
158
 
159
 
160
- ## 处理advance docs
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  advance_docs = defaultdict(lambda: defaultdict(dict))
162
  advance_docs.update(config.get("advance_docs", {}))
 
 
163
  def update_doc_config(two_column_pdf):
164
  global advance_docs
165
  advance_docs["pdf"]["two_column"] = two_column_pdf
166
 
167
  logging.info(f"更新后的文件参数为:{advance_docs}")
168
 
169
- ## 处理gradio.launch参数
 
170
  server_name = config.get("server_name", None)
171
  server_port = config.get("server_port", None)
172
  if server_name is None:
@@ -188,3 +274,7 @@ except ValueError:
188
  pass
189
 
190
  share = config.get("share", False)
 
 
 
 
11
 
12
  __all__ = [
13
  "my_api_key",
14
+ "sensitive_id",
15
  "authflag",
16
  "auth_list",
17
  "dockerflag",
18
  "retrieve_proxy",
 
19
  "advance_docs",
20
  "update_doc_config",
21
  "usage_limit",
23
  "server_name",
24
  "server_port",
25
  "share",
26
+ "check_update",
27
+ "latex_delimiters_set",
28
  "hide_history_when_not_logged_in",
29
+ "default_chuanhu_assistant_model",
30
+ "show_api_billing"
31
  ]
32
 
33
  # 添加一个统一的config文件,避免文件过多造成的疑惑(优先级最低)
38
  else:
39
  config = {}
40
 
41
+
42
+ def load_config_to_environ(key_list):
43
+ global config
44
+ for key in 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文件,正在进行迁移...")
67
  logging.info("检测到auth.json文件,正在进行迁移...")
68
  auth_list = []
69
  with open("auth.json", "r", encoding='utf-8') as f:
70
+ auth = json.load(f)
71
+ for _ in auth:
72
+ if auth[_]["username"] and auth[_]["password"]:
73
+ auth_list.append((auth[_]["username"], auth[_]["password"]))
74
+ else:
75
+ logging.error("请检查auth.json文件中的用户名和密码!")
76
+ sys.exit(1)
77
  config["users"] = auth_list
78
  os.rename("auth.json", "auth(deprecated).json")
79
  with open("config.json", "w", encoding='utf-8') as f:
80
  json.dump(config, f, indent=4, ensure_ascii=False)
81
 
82
+ # 处理docker if we are running in Docker
83
  dockerflag = config.get("dockerflag", False)
84
  if os.environ.get("dockerrun") == "yes":
85
  dockerflag = True
86
 
87
+ # 处理 api-key 以及 允许的用户列表
88
  my_api_key = config.get("openai_api_key", "")
89
  my_api_key = os.environ.get("OPENAI_API_KEY", my_api_key)
90
+ os.environ["OPENAI_API_KEY"] = my_api_key
91
+ os.environ["OPENAI_EMBEDDING_API_KEY"] = my_api_key
92
+
93
+ if config.get("legacy_api_usage", False):
94
+ sensitive_id = my_api_key
95
+ 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"])
102
+ logging.info(f"已添加额外的模型:{config['extra_models']}")
103
+
104
+ google_palm_api_key = config.get("google_palm_api_key", "")
105
+ google_palm_api_key = os.environ.get(
106
+ "GOOGLE_PALM_API_KEY", google_palm_api_key)
107
+ os.environ["GOOGLE_PALM_API_KEY"] = google_palm_api_key
108
 
109
  xmchat_api_key = config.get("xmchat_api_key", "")
110
  os.environ["XMCHAT_API_KEY"] = xmchat_api_key
114
  minimax_group_id = config.get("minimax_group_id", "")
115
  os.environ["MINIMAX_GROUP_ID"] = minimax_group_id
116
 
117
+ midjourney_proxy_api_base = config.get("midjourney_proxy_api_base", "")
118
+ os.environ["MIDJOURNEY_PROXY_API_BASE"] = midjourney_proxy_api_base
119
+ midjourney_proxy_api_secret = config.get("midjourney_proxy_api_secret", "")
120
+ os.environ["MIDJOURNEY_PROXY_API_SECRET"] = midjourney_proxy_api_secret
121
+ midjourney_discord_proxy_url = config.get("midjourney_discord_proxy_url", "")
122
+ 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
+
129
 
130
  usage_limit = os.environ.get("USAGE_LIMIT", config.get("usage_limit", 120))
131
 
132
+ # 多账户机制
133
+ multi_api_key = config.get("multi_api_key", False) # 是否开启多账户机制
134
  if multi_api_key:
135
  api_key_list = config.get("api_key_list", [])
136
  if len(api_key_list) == 0:
138
  sys.exit(1)
139
  shared.state.set_api_key_queue(api_key_list)
140
 
141
+ auth_list = config.get("users", []) # 实际上是使用者的列表
142
  authflag = len(auth_list) > 0 # 是否开启认证的状态值,改为判断auth_list长度
143
 
144
  # 处理自定义的api_host,优先读环境变量的配置,如果存在则自动装配
145
+ api_host = os.environ.get(
146
+ "OPENAI_API_BASE", config.get("openai_api_base", None))
147
  if api_host is not None:
148
  shared.state.set_api_host(api_host)
149
+ os.environ["OPENAI_API_BASE"] = f"{api_host}/v1"
150
+ logging.info(f"OpenAI API Base set to: {os.environ['OPENAI_API_BASE']}")
151
 
152
+ default_chuanhu_assistant_model = config.get(
153
+ "default_chuanhu_assistant_model", "gpt-3.5-turbo")
154
  for x in ["GOOGLE_CSE_ID", "GOOGLE_API_KEY", "WOLFRAM_ALPHA_APPID", "SERPAPI_API_KEY"]:
155
  if config.get(x, None) is not None:
156
  os.environ[x] = config[x]
157
 
158
+
159
  @contextmanager
160
+ def retrieve_openai_api(api_key=None):
161
  old_api_key = os.environ.get("OPENAI_API_KEY", "")
162
  if api_key is None:
163
  os.environ["OPENAI_API_KEY"] = my_api_key
167
  yield api_key
168
  os.environ["OPENAI_API_KEY"] = old_api_key
169
 
 
 
 
 
 
 
170
 
171
+
172
+ # 处理代理:
173
+ http_proxy = os.environ.get("HTTP_PROXY", "")
174
+ https_proxy = os.environ.get("HTTPS_PROXY", "")
175
+ http_proxy = config.get("http_proxy", http_proxy)
176
+ https_proxy = config.get("https_proxy", https_proxy)
177
 
178
  # 重置系统变量,在不需要设置的时候不设置环境变量,以免引起全局代理报错
179
  os.environ["HTTP_PROXY"] = ""
180
  os.environ["HTTPS_PROXY"] = ""
181
 
182
+ local_embedding = config.get("local_embedding", False) # 是否使用本地embedding
183
+
184
 
185
  @contextmanager
186
  def retrieve_proxy(proxy=None):
197
  old_var = os.environ["HTTP_PROXY"], os.environ["HTTPS_PROXY"]
198
  os.environ["HTTP_PROXY"] = http_proxy
199
  os.environ["HTTPS_PROXY"] = https_proxy
200
+ yield http_proxy, https_proxy # return new proxy
201
 
202
  # return old proxy
203
  os.environ["HTTP_PROXY"], os.environ["HTTPS_PROXY"] = old_var
204
 
205
 
206
+ # 处理latex options
207
+ user_latex_option = config.get("latex_option", "default")
208
+ if user_latex_option == "default":
209
+ latex_delimiters_set = [
210
+ {"left": "$$", "right": "$$", "display": True},
211
+ {"left": "$", "right": "$", "display": False},
212
+ {"left": "\\(", "right": "\\)", "display": False},
213
+ {"left": "\\[", "right": "\\]", "display": True},
214
+ ]
215
+ elif user_latex_option == "strict":
216
+ latex_delimiters_set = [
217
+ {"left": "$$", "right": "$$", "display": True},
218
+ {"left": "\\(", "right": "\\)", "display": False},
219
+ {"left": "\\[", "right": "\\]", "display": True},
220
+ ]
221
+ elif user_latex_option == "all":
222
+ latex_delimiters_set = [
223
+ {"left": "$$", "right": "$$", "display": True},
224
+ {"left": "$", "right": "$", "display": False},
225
+ {"left": "\\(", "right": "\\)", "display": False},
226
+ {"left": "\\[", "right": "\\]", "display": True},
227
+ {"left": "\\begin{equation}", "right": "\\end{equation}", "display": True},
228
+ {"left": "\\begin{align}", "right": "\\end{align}", "display": True},
229
+ {"left": "\\begin{alignat}", "right": "\\end{alignat}", "display": True},
230
+ {"left": "\\begin{gather}", "right": "\\end{gather}", "display": True},
231
+ {"left": "\\begin{CD}", "right": "\\end{CD}", "display": True},
232
+ ]
233
+ elif user_latex_option == "disabled":
234
+ latex_delimiters_set = []
235
+ else:
236
+ latex_delimiters_set = [
237
+ {"left": "$$", "right": "$$", "display": True},
238
+ {"left": "$", "right": "$", "display": False},
239
+ {"left": "\\(", "right": "\\)", "display": False},
240
+ {"left": "\\[", "right": "\\]", "display": True},
241
+ ]
242
+
243
+ # 处理advance docs
244
  advance_docs = defaultdict(lambda: defaultdict(dict))
245
  advance_docs.update(config.get("advance_docs", {}))
246
+
247
+
248
  def update_doc_config(two_column_pdf):
249
  global advance_docs
250
  advance_docs["pdf"]["two_column"] = two_column_pdf
251
 
252
  logging.info(f"更新后的文件参数为:{advance_docs}")
253
 
254
+
255
+ # 处理gradio.launch参数
256
  server_name = config.get("server_name", None)
257
  server_port = config.get("server_port", None)
258
  if server_name is None:
274
  pass
275
 
276
  share = config.get("share", False)
277
+
278
+ # avatar
279
+ bot_avatar = config.get("bot_avatar", "default")
280
+ user_avatar = config.get("user_avatar", "default")
modules/index_func.py CHANGED
@@ -1,7 +1,7 @@
1
  import os
2
  import logging
3
 
4
- import colorama
5
  import PyPDF2
6
  from tqdm import tqdm
7
 
@@ -10,19 +10,6 @@ from modules.utils import *
10
  from modules.config import local_embedding
11
 
12
 
13
- def get_index_name(file_src):
14
- file_paths = [x.name for x in file_src]
15
- file_paths.sort(key=lambda x: os.path.basename(x))
16
-
17
- md5_hash = hashlib.md5()
18
- for file_path in file_paths:
19
- with open(file_path, "rb") as f:
20
- while chunk := f.read(8192):
21
- md5_hash.update(chunk)
22
-
23
- return md5_hash.hexdigest()
24
-
25
-
26
  def get_documents(file_src):
27
  from langchain.schema import Document
28
  from langchain.text_splitter import TokenTextSplitter
@@ -47,11 +34,12 @@ def get_documents(file_src):
47
  pdftext = parse_pdf(filepath, two_column).text
48
  except:
49
  pdftext = ""
50
- with open(filepath, "rb", encoding="utf-8") as pdfFileObj:
51
  pdfReader = PyPDF2.PdfReader(pdfFileObj)
52
  for page in tqdm(pdfReader.pages):
53
  pdftext += page.extract_text()
54
- texts = [Document(page_content=pdftext, metadata={"source": filepath})]
 
55
  elif file_type == ".docx":
56
  logging.debug("Loading Word...")
57
  from langchain.document_loaders import UnstructuredWordDocumentLoader
@@ -72,7 +60,8 @@ def get_documents(file_src):
72
  text_list = excel_to_string(filepath)
73
  texts = []
74
  for elem in text_list:
75
- texts.append(Document(page_content=elem, metadata={"source": filepath}))
 
76
  else:
77
  logging.debug("Loading text file...")
78
  from langchain.document_loaders import TextLoader
@@ -111,14 +100,20 @@ def construct_index(
111
  embedding_limit = None if embedding_limit == 0 else embedding_limit
112
  separator = " " if separator == "" else separator
113
 
114
- index_name = get_index_name(file_src)
115
  index_path = f"./index/{index_name}"
116
  if local_embedding:
117
  from langchain.embeddings.huggingface import HuggingFaceEmbeddings
118
- embeddings = HuggingFaceEmbeddings(model_name = "sentence-transformers/distiluse-base-multilingual-cased-v2")
 
119
  else:
120
  from langchain.embeddings import OpenAIEmbeddings
121
- embeddings = OpenAIEmbeddings(openai_api_base=os.environ.get("OPENAI_API_BASE", None), openai_api_key=os.environ.get("OPENAI_EMBEDDING_API_KEY", api_key))
 
 
 
 
 
122
  if os.path.exists(index_path):
123
  logging.info("找到了缓存的索引文件,加载中……")
124
  return FAISS.load_local(index_path, embeddings)
1
  import os
2
  import logging
3
 
4
+ import hashlib
5
  import PyPDF2
6
  from tqdm import tqdm
7
 
10
  from modules.config import local_embedding
11
 
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  def get_documents(file_src):
14
  from langchain.schema import Document
15
  from langchain.text_splitter import TokenTextSplitter
34
  pdftext = parse_pdf(filepath, two_column).text
35
  except:
36
  pdftext = ""
37
+ with open(filepath, "rb") as pdfFileObj:
38
  pdfReader = PyPDF2.PdfReader(pdfFileObj)
39
  for page in tqdm(pdfReader.pages):
40
  pdftext += page.extract_text()
41
+ texts = [Document(page_content=pdftext,
42
+ metadata={"source": filepath})]
43
  elif file_type == ".docx":
44
  logging.debug("Loading Word...")
45
  from langchain.document_loaders import UnstructuredWordDocumentLoader
60
  text_list = excel_to_string(filepath)
61
  texts = []
62
  for elem in text_list:
63
+ texts.append(Document(page_content=elem,
64
+ metadata={"source": filepath}))
65
  else:
66
  logging.debug("Loading text file...")
67
  from langchain.document_loaders import TextLoader
100
  embedding_limit = None if embedding_limit == 0 else embedding_limit
101
  separator = " " if separator == "" else separator
102
 
103
+ index_name = get_file_hash(file_src)
104
  index_path = f"./index/{index_name}"
105
  if local_embedding:
106
  from langchain.embeddings.huggingface import HuggingFaceEmbeddings
107
+ embeddings = HuggingFaceEmbeddings(
108
+ model_name="sentence-transformers/distiluse-base-multilingual-cased-v2")
109
  else:
110
  from langchain.embeddings import OpenAIEmbeddings
111
+ if os.environ.get("OPENAI_API_TYPE", "openai") == "openai":
112
+ embeddings = OpenAIEmbeddings(openai_api_base=os.environ.get(
113
+ "OPENAI_API_BASE", None), openai_api_key=os.environ.get("OPENAI_EMBEDDING_API_KEY", api_key))
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)
modules/models/Google_PaLM.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .base_model import BaseLLMModel
2
+ import google.generativeai as palm
3
+
4
+ class Google_PaLM_Client(BaseLLMModel):
5
+ def __init__(self, model_name, api_key, user_name="") -> None:
6
+ super().__init__(model_name=model_name, user=user_name)
7
+ self.api_key = api_key
8
+
9
+ def _get_palm_style_input(self):
10
+ new_history = []
11
+ for item in self.history:
12
+ if item["role"] == "user":
13
+ new_history.append({'author': '1', 'content': item["content"]})
14
+ else:
15
+ new_history.append({'author': '0', 'content': item["content"]})
16
+ return new_history
17
+
18
+ def get_answer_at_once(self):
19
+ palm.configure(api_key=self.api_key)
20
+ messages = self._get_palm_style_input()
21
+ response = palm.chat(context=self.system_prompt, messages=messages, temperature=self.temperature, top_p=self.top_p)
22
+ if response.last is not None:
23
+ return response.last, len(response.last)
24
+ else:
25
+ reasons = '\n\n'.join(reason['reason'].name for reason in response.filters)
26
+ return "由于下面的原因,Google 拒绝返回 PaLM 的回答:\n\n" + reasons, 0
modules/models/__pycache__/ChuanhuAgent.cpython-311.pyc CHANGED
Binary files a/modules/models/__pycache__/ChuanhuAgent.cpython-311.pyc and b/modules/models/__pycache__/ChuanhuAgent.cpython-311.pyc differ
modules/models/__pycache__/Google_PaLM.cpython-311.pyc ADDED
Binary file (2.64 kB). View file
modules/models/__pycache__/azure.cpython-311.pyc ADDED
Binary file (1.18 kB). View file
modules/models/__pycache__/base_model.cpython-311.pyc CHANGED
Binary files a/modules/models/__pycache__/base_model.cpython-311.pyc and b/modules/models/__pycache__/base_model.cpython-311.pyc differ
modules/models/__pycache__/base_model.cpython-39.pyc CHANGED
Binary files a/modules/models/__pycache__/base_model.cpython-39.pyc and b/modules/models/__pycache__/base_model.cpython-39.pyc differ
modules/models/__pycache__/models.cpython-311.pyc CHANGED
Binary files a/modules/models/__pycache__/models.cpython-311.pyc and b/modules/models/__pycache__/models.cpython-311.pyc differ
modules/models/__pycache__/models.cpython-39.pyc CHANGED
Binary files a/modules/models/__pycache__/models.cpython-39.pyc and b/modules/models/__pycache__/models.cpython-39.pyc differ
modules/models/azure.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain.chat_models import AzureChatOpenAI
2
+ import os
3
+
4
+ from .base_model import Base_Chat_Langchain_Client
5
+
6
+ # load_config_to_environ(["azure_openai_api_key", "azure_api_base_url", "azure_openai_api_version", "azure_deployment_name"])
7
+
8
+ class Azure_OpenAI_Client(Base_Chat_Langchain_Client):
9
+ def setup_model(self):
10
+ # inplement this to setup the model then return it
11
+ return AzureChatOpenAI(
12
+ openai_api_base=os.environ["AZURE_OPENAI_API_BASE_URL"],
13
+ openai_api_version=os.environ["AZURE_OPENAI_API_VERSION"],
14
+ deployment_name=os.environ["AZURE_DEPLOYMENT_NAME"],
15
+ openai_api_key=os.environ["AZURE_OPENAI_API_KEY"],
16
+ openai_api_type="azure",
17
+ )
modules/models/base_model.py CHANGED
@@ -29,6 +29,8 @@ from langchain.input import print_text
29
  from langchain.schema import AgentAction, AgentFinish, LLMResult
30
  from threading import Thread, Condition
31
  from collections import deque
 
 
32
 
33
  from ..presets import *
34
  from ..index_func import *
@@ -36,6 +38,7 @@ from ..utils import *
36
  from .. import shared
37
  from ..config import retrieve_proxy
38
 
 
39
  class CallbackToIterator:
40
  def __init__(self):
41
  self.queue = deque()
@@ -52,7 +55,8 @@ class CallbackToIterator:
52
 
53
  def __next__(self):
54
  with self.cond:
55
- while not self.queue and not self.finished: # Wait for a value to be added to the queue.
 
56
  self.cond.wait()
57
  if not self.queue:
58
  raise StopIteration()
@@ -63,6 +67,7 @@ class CallbackToIterator:
63
  self.finished = True
64
  self.cond.notify() # Wake up the generator if it's waiting.
65
 
 
66
  def get_action_description(text):
67
  match = re.search('```(.*?)```', text, re.S)
68
  json_text = match.group(1)
@@ -72,10 +77,11 @@ def get_action_description(text):
72
  action_name = json_dict['action']
73
  action_input = json_dict['action_input']
74
  if action_name != "Final Answer":
75
- return f'<p style="font-size: smaller; color: gray;">{action_name}: {action_input}</p>'
76
  else:
77
  return ""
78
 
 
79
  class ChuanhuCallbackHandler(BaseCallbackHandler):
80
 
81
  def __init__(self, callback) -> None:
@@ -117,6 +123,10 @@ class ChuanhuCallbackHandler(BaseCallbackHandler):
117
  """Run on new LLM token. Only available when streaming is enabled."""
118
  self.callback(token)
119
 
 
 
 
 
120
 
121
  class ModelType(Enum):
122
  Unknown = -1
@@ -129,6 +139,9 @@ class ModelType(Enum):
129
  YuanAI = 6
130
  Minimax = 7
131
  ChuanhuAgent = 8
 
 
 
132
 
133
  @classmethod
134
  def get_type(cls, model_name: str):
@@ -152,6 +165,12 @@ class ModelType(Enum):
152
  model_type = ModelType.Minimax
153
  elif "川虎助理" in model_name_lower:
154
  model_type = ModelType.ChuanhuAgent
 
 
 
 
 
 
155
  else:
156
  model_type = ModelType.Unknown
157
  return model_type
@@ -161,7 +180,7 @@ class BaseLLMModel:
161
  def __init__(
162
  self,
163
  model_name,
164
- system_prompt="",
165
  temperature=1.0,
166
  top_p=1.0,
167
  n_choices=1,
@@ -201,7 +220,8 @@ class BaseLLMModel:
201
  conversations are stored in self.history, with the most recent question, in OpenAI format
202
  should return a generator, each time give the next word (str) in the answer
203
  """
204
- logging.warning("stream predict not implemented, using at once predict instead")
 
205
  response, _ = self.get_answer_at_once()
206
  yield response
207
 
@@ -212,7 +232,8 @@ class BaseLLMModel:
212
  the answer (str)
213
  total token count (int)
214
  """
215
- logging.warning("at once predict not implemented, using stream predict instead")
 
216
  response_iter = self.get_answer_stream_iter()
217
  count = 0
218
  for response in response_iter:
@@ -246,7 +267,8 @@ class BaseLLMModel:
246
  stream_iter = self.get_answer_stream_iter()
247
 
248
  if display_append:
249
- display_append = "<hr>" +display_append
 
250
  for partial_text in stream_iter:
251
  chatbot[-1] = (chatbot[-1][0], partial_text + display_append)
252
  self.all_token_counts[-1] += 1
@@ -273,9 +295,11 @@ class BaseLLMModel:
273
  self.history[-2] = construct_user(fake_input)
274
  chatbot[-1] = (chatbot[-1][0], ai_reply + display_append)
275
  if fake_input is not None:
276
- self.all_token_counts[-1] += count_token(construct_assistant(ai_reply))
 
277
  else:
278
- self.all_token_counts[-1] = total_token_count - sum(self.all_token_counts)
 
279
  status_text = self.token_message()
280
  return chatbot, status_text
281
 
@@ -299,10 +323,13 @@ class BaseLLMModel:
299
  from langchain.chat_models import ChatOpenAI
300
  from langchain.callbacks import StdOutCallbackHandler
301
  prompt_template = "Write a concise summary of the following:\n\n{text}\n\nCONCISE SUMMARY IN " + language + ":"
302
- PROMPT = PromptTemplate(template=prompt_template, input_variables=["text"])
 
303
  llm = ChatOpenAI()
304
- chain = load_summarize_chain(llm, chain_type="map_reduce", return_intermediate_steps=True, map_prompt=PROMPT, combine_prompt=PROMPT)
305
- summary = chain({"input_documents": list(index.docstore.__dict__["_dict"].values())}, return_only_outputs=True)["output_text"]
 
 
306
  print(i18n("总结") + f": {summary}")
307
  chatbot.append([i18n("上传了")+str(len(files))+"个文件", summary])
308
  return chatbot, status
@@ -323,9 +350,12 @@ class BaseLLMModel:
323
  msg = "索引获取成功,生成回答中……"
324
  logging.info(msg)
325
  with retrieve_proxy():
326
- retriever = VectorStoreRetriever(vectorstore=index, search_type="similarity_score_threshold",search_kwargs={"k":6, "score_threshold": 0.5})
327
- relevant_documents = retriever.get_relevant_documents(real_inputs)
328
- reference_results = [[d.page_content.strip("�"), os.path.basename(d.metadata["source"])] for d in relevant_documents]
 
 
 
329
  reference_results = add_source_numbers(reference_results)
330
  display_append = add_details(reference_results)
331
  display_append = "\n\n" + "".join(display_append)
@@ -348,10 +378,12 @@ class BaseLLMModel:
348
  reference_results.append([result['body'], result['href']])
349
  display_append.append(
350
  # f"{idx+1}. [{domain_name}]({result['href']})\n"
351
- f"<li><a href=\"{result['href']}\" target=\"_blank\">{result['title']}</a></li>\n"
352
  )
353
  reference_results = add_source_numbers(reference_results)
354
- display_append = "<ol>\n\n" + "".join(display_append) + "</ol>"
 
 
355
  real_inputs = (
356
  replace_today(WEBSEARCH_PTOMPT_TEMPLATE)
357
  .replace("{query}", real_inputs)
@@ -375,14 +407,16 @@ class BaseLLMModel:
375
 
376
  status_text = "开始生成回答……"
377
  logging.info(
378
- "用户" + f"{self.user_identifier}" + "的输入为:" + colorama.Fore.BLUE + f"{inputs}" + colorama.Style.RESET_ALL
 
379
  )
380
  if should_check_token_count:
381
  yield chatbot + [(inputs, "")], status_text
382
  if reply_language == "跟随问题语言(不稳定)":
383
  reply_language = "the same language as the question, such as English, 中文, 日本語, Español, Français, or Deutsch."
384
 
385
- limited_context, fake_inputs, display_append, inputs, chatbot = self.prepare_inputs(real_inputs=inputs, use_websearch=use_websearch, files=files, reply_language=reply_language, chatbot=chatbot)
 
386
  yield chatbot + [(fake_inputs, "")], status_text
387
 
388
  if (
@@ -434,7 +468,7 @@ class BaseLLMModel:
434
  yield chatbot, status_text
435
  except Exception as e:
436
  traceback.print_exc()
437
- status_text = STANDARD_ERROR_MSG + str(e)
438
  yield chatbot, status_text
439
 
440
  if len(self.history) > 1 and self.history[-1]["content"] != inputs:
@@ -568,10 +602,13 @@ class BaseLLMModel:
568
  self.system_prompt = new_system_prompt
569
 
570
  def set_key(self, new_access_key):
571
- self.api_key = new_access_key.strip()
572
- msg = i18n("API密钥更改为了") + hide_middle_chars(self.api_key)
573
- logging.info(msg)
574
- return self.api_key, msg
 
 
 
575
 
576
  def set_single_turn(self, new_single_turn):
577
  self.single_turn = new_single_turn
@@ -580,7 +617,8 @@ class BaseLLMModel:
580
  self.history = []
581
  self.all_token_counts = []
582
  self.interrupted = False
583
- pathlib.Path(os.path.join(HISTORY_DIR, self.user_identifier, new_auto_history_filename(os.path.join(HISTORY_DIR, self.user_identifier)))).touch()
 
584
  return [], self.token_message([0])
585
 
586
  def delete_first_conversation(self):
@@ -623,7 +661,8 @@ class BaseLLMModel:
623
 
624
  def auto_save(self, chatbot):
625
  history_file_path = get_history_filepath(self.user_identifier)
626
- save_file(history_file_path, self.system_prompt, self.history, chatbot, self.user_identifier)
 
627
 
628
  def export_markdown(self, filename, chatbot, user_name):
629
  if filename == "":
@@ -639,7 +678,8 @@ class BaseLLMModel:
639
  filename = filename.name
640
  try:
641
  if "/" not in filename:
642
- history_file_path = os.path.join(HISTORY_DIR, user_name, filename)
 
643
  else:
644
  history_file_path = filename
645
  with open(history_file_path, "r", encoding="utf-8") as f:
@@ -665,15 +705,33 @@ class BaseLLMModel:
665
  logging.info(f"没有找到对话历史记录 {filename}")
666
  return gr.update(), self.system_prompt, gr.update()
667
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
668
  def auto_load(self):
669
  if self.user_identifier == "":
670
  self.reset()
671
  return self.system_prompt, gr.update()
672
  history_file_path = get_history_filepath(self.user_identifier)
673
- filename, system_prompt, chatbot = self.load_chat_history(history_file_path, self.user_identifier)
 
674
  return system_prompt, chatbot
675
 
676
-
677
  def like(self):
678
  """like the last response, implement if needed
679
  """
@@ -683,3 +741,47 @@ class BaseLLMModel:
683
  """dislike the last response, implement if needed
684
  """
685
  return gr.update()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  from langchain.schema import AgentAction, AgentFinish, LLMResult
30
  from threading import Thread, Condition
31
  from collections import deque
32
+ from langchain.chat_models.base import BaseChatModel
33
+ from langchain.schema import HumanMessage, AIMessage, SystemMessage, BaseMessage
34
 
35
  from ..presets import *
36
  from ..index_func import *
38
  from .. import shared
39
  from ..config import retrieve_proxy
40
 
41
+
42
  class CallbackToIterator:
43
  def __init__(self):
44
  self.queue = deque()
55
 
56
  def __next__(self):
57
  with self.cond:
58
+ # Wait for a value to be added to the queue.
59
+ while not self.queue and not self.finished:
60
  self.cond.wait()
61
  if not self.queue:
62
  raise StopIteration()
67
  self.finished = True
68
  self.cond.notify() # Wake up the generator if it's waiting.
69
 
70
+
71
  def get_action_description(text):
72
  match = re.search('```(.*?)```', text, re.S)
73
  json_text = match.group(1)
77
  action_name = json_dict['action']
78
  action_input = json_dict['action_input']
79
  if action_name != "Final Answer":
80
+ return f'<!-- S O PREFIX --><p class="agent-prefix">{action_name}: {action_input}\n\n</p><!-- E O PREFIX -->'
81
  else:
82
  return ""
83
 
84
+
85
  class ChuanhuCallbackHandler(BaseCallbackHandler):
86
 
87
  def __init__(self, callback) -> None:
123
  """Run on new LLM token. Only available when streaming is enabled."""
124
  self.callback(token)
125
 
126
+ def on_chat_model_start(self, serialized: Dict[str, Any], messages: List[List[BaseMessage]], **kwargs: Any) -> Any:
127
+ """Run when a chat model starts running."""
128
+ pass
129
+
130
 
131
  class ModelType(Enum):
132
  Unknown = -1
139
  YuanAI = 6
140
  Minimax = 7
141
  ChuanhuAgent = 8
142
+ GooglePaLM = 9
143
+ LangchainChat = 10
144
+ Midjourney = 11
145
 
146
  @classmethod
147
  def get_type(cls, model_name: str):
165
  model_type = ModelType.Minimax
166
  elif "川虎助理" in model_name_lower:
167
  model_type = ModelType.ChuanhuAgent
168
+ elif "palm" in model_name_lower:
169
+ model_type = ModelType.GooglePaLM
170
+ elif "midjourney" in model_name_lower:
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.Unknown
176
  return model_type
180
  def __init__(
181
  self,
182
  model_name,
183
+ system_prompt=INITIAL_SYSTEM_PROMPT,
184
  temperature=1.0,
185
  top_p=1.0,
186
  n_choices=1,
220
  conversations are stored in self.history, with the most recent question, in OpenAI format
221
  should return a generator, each time give the next word (str) in the answer
222
  """
223
+ logging.warning(
224
+ "stream predict not implemented, using at once predict instead")
225
  response, _ = self.get_answer_at_once()
226
  yield response
227
 
232
  the answer (str)
233
  total token count (int)
234
  """
235
+ logging.warning(
236
+ "at once predict not implemented, using stream predict instead")
237
  response_iter = self.get_answer_stream_iter()
238
  count = 0
239
  for response in response_iter:
267
  stream_iter = self.get_answer_stream_iter()
268
 
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] += 1
295
  self.history[-2] = construct_user(fake_input)
296
  chatbot[-1] = (chatbot[-1][0], ai_reply + display_append)
297
  if fake_input is not None:
298
+ self.all_token_counts[-1] += count_token(
299
+ construct_assistant(ai_reply))
300
  else:
301
+ self.all_token_counts[-1] = total_token_count - \
302
+ sum(self.all_token_counts)
303
  status_text = self.token_message()
304
  return chatbot, status_text
305
 
323
  from langchain.chat_models import ChatOpenAI
324
  from langchain.callbacks import StdOutCallbackHandler
325
  prompt_template = "Write a concise summary of the following:\n\n{text}\n\nCONCISE SUMMARY IN " + language + ":"
326
+ PROMPT = PromptTemplate(
327
+ template=prompt_template, input_variables=["text"])
328
  llm = ChatOpenAI()
329
+ chain = load_summarize_chain(
330
+ llm, chain_type="map_reduce", return_intermediate_steps=True, map_prompt=PROMPT, combine_prompt=PROMPT)
331
+ summary = chain({"input_documents": list(index.docstore.__dict__[
332
+ "_dict"].values())}, return_only_outputs=True)["output_text"]
333
  print(i18n("总结") + f": {summary}")
334
  chatbot.append([i18n("上传了")+str(len(files))+"个文件", summary])
335
  return chatbot, status
350
  msg = "索引获取成功,生成回答中……"
351
  logging.info(msg)
352
  with retrieve_proxy():
353
+ retriever = VectorStoreRetriever(vectorstore=index, search_type="similarity_score_threshold", search_kwargs={
354
+ "k": 6, "score_threshold": 0.5})
355
+ relevant_documents = retriever.get_relevant_documents(
356
+ real_inputs)
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)
378
  reference_results.append([result['body'], result['href']])
379
  display_append.append(
380
  # f"{idx+1}. [{domain_name}]({result['href']})\n"
381
+ f"<a href=\"{result['href']}\" target=\"_blank\">{idx+1}.&nbsp;{result['title']}</a>"
382
  )
383
  reference_results = add_source_numbers(reference_results)
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
  replace_today(WEBSEARCH_PTOMPT_TEMPLATE)
389
  .replace("{query}", real_inputs)
407
 
408
  status_text = "开始生成回答……"
409
  logging.info(
410
+ "用户" + f"{self.user_identifier}" + "的输入为:" +
411
+ colorama.Fore.BLUE + f"{inputs}" + colorama.Style.RESET_ALL
412
  )
413
  if should_check_token_count:
414
  yield chatbot + [(inputs, "")], status_text
415
  if reply_language == "跟随问题语言(不稳定)":
416
  reply_language = "the same language as the question, such as English, 中文, 日本語, Español, Français, or Deutsch."
417
 
418
+ limited_context, fake_inputs, display_append, inputs, chatbot = self.prepare_inputs(
419
+ real_inputs=inputs, use_websearch=use_websearch, files=files, reply_language=reply_language, chatbot=chatbot)
420
  yield chatbot + [(fake_inputs, "")], status_text
421
 
422
  if (
468
  yield chatbot, status_text
469
  except Exception as e:
470
  traceback.print_exc()
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"] != inputs:
602
  self.system_prompt = new_system_prompt
603
 
604
  def set_key(self, new_access_key):
605
+ if "*" not in new_access_key:
606
+ self.api_key = new_access_key.strip()
607
+ msg = i18n("API密钥更改为了") + hide_middle_chars(self.api_key)
608
+ logging.info(msg)
609
+ return self.api_key, msg
610
+ else:
611
+ return gr.update(), gr.update()
612
 
613
  def set_single_turn(self, new_single_turn):
614
  self.single_turn = new_single_turn
617
  self.history = []
618
  self.all_token_counts = []
619
  self.interrupted = False
620
+ pathlib.Path(os.path.join(HISTORY_DIR, self.user_identifier, new_auto_history_filename(
621
+ os.path.join(HISTORY_DIR, self.user_identifier)))).touch()
622
  return [], self.token_message([0])
623
 
624
  def delete_first_conversation(self):
661
 
662
  def auto_save(self, chatbot):
663
  history_file_path = get_history_filepath(self.user_identifier)
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):
668
  if filename == "":
678
  filename = filename.name
679
  try:
680
  if "/" not in filename:
681
+ history_file_path = os.path.join(
682
+ HISTORY_DIR, user_name, filename)
683
  else:
684
  history_file_path = filename
685
  with open(history_file_path, "r", encoding="utf-8") as f:
705
  logging.info(f"没有找到对话历史记录 {filename}")
706
  return gr.update(), self.system_prompt, gr.update()
707
 
708
+ def delete_chat_history(self, filename, user_name):
709
+ if filename == "CANCELED":
710
+ return gr.update(), gr.update(), gr.update()
711
+ if filename == "":
712
+ return i18n("你没有选择任何对话历史"), gr.update(), gr.update()
713
+ if not filename.endswith(".json"):
714
+ filename += ".json"
715
+ if "/" not in filename:
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
+ return i18n("删除对话历史成功"), get_history_names(False, user_name), []
722
+ except:
723
+ logging.info(f"删除对话历史失败 {history_file_path}")
724
+ return i18n("对话历史")+filename+i18n("已经被删除啦"), gr.update(), gr.update()
725
+
726
  def auto_load(self):
727
  if self.user_identifier == "":
728
  self.reset()
729
  return self.system_prompt, gr.update()
730
  history_file_path = get_history_filepath(self.user_identifier)
731
+ filename, system_prompt, chatbot = self.load_chat_history(
732
+ history_file_path, self.user_identifier)
733
  return system_prompt, chatbot
734
 
 
735
  def like(self):
736
  """like the last response, implement if needed
737
  """
741
  """dislike the last response, implement if needed
742
  """
743
  return gr.update()
744
+
745
+
746
+ class Base_Chat_Langchain_Client(BaseLLMModel):
747
+ def __init__(self, model_name, user_name=""):
748
+ super().__init__(model_name, user=user_name)
749
+ self.need_api_key = False
750
+ self.model = self.setup_model()
751
+
752
+ def setup_model(self):
753
+ # inplement this to setup the model then return it
754
+ pass
755
+
756
+ def _get_langchain_style_history(self):
757
+ history = [SystemMessage(content=self.system_prompt)]
758
+ for i in self.history:
759
+ if i["role"] == "user":
760
+ history.append(HumanMessage(content=i["content"]))
761
+ elif i["role"] == "assistant":
762
+ history.append(AIMessage(content=i["content"]))
763
+ return history
764
+
765
+ def get_answer_at_once(self):
766
+ assert isinstance(
767
+ self.model, BaseChatModel), "model is not instance of LangChain BaseChatModel"
768
+ history = self._get_langchain_style_history()
769
+ response = self.model.generate(history)
770
+ return response.content, sum(response.content)
771
+
772
+ def get_answer_stream_iter(self):
773
+ it = CallbackToIterator()
774
+ assert isinstance(
775
+ self.model, BaseChatModel), "model is not instance of LangChain BaseChatModel"
776
+ history = self._get_langchain_style_history()
777
+
778
+ def thread_func():
779
+ self.model(messages=history, callbacks=[
780
+ ChuanhuCallbackHandler(it.callback)])
781
+ it.finish()
782
+ t = Thread(target=thread_func)
783
+ t.start()
784
+ partial_text = ""
785
+ for value in it:
786
+ partial_text += value
787
+ yield partial_text
modules/models/midjourney.py ADDED
@@ -0,0 +1,385 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import io
3
+ import json
4
+ import logging
5
+ import pathlib
6
+ import time
7
+ import tempfile
8
+ import os
9
+
10
+ from datetime import datetime
11
+
12
+ import requests
13
+ import tiktoken
14
+ from PIL import Image
15
+
16
+ from modules.config import retrieve_proxy
17
+ from modules.models.models import XMChat
18
+
19
+ mj_proxy_api_base = os.getenv("MIDJOURNEY_PROXY_API_BASE")
20
+ mj_discord_proxy_url = os.getenv("MIDJOURNEY_DISCORD_PROXY_URL")
21
+ mj_temp_folder = os.getenv("MIDJOURNEY_TEMP_FOLDER")
22
+
23
+
24
+ class Midjourney_Client(XMChat):
25
+
26
+ class FetchDataPack:
27
+ """
28
+ A class to store data for current fetching data from Midjourney API
29
+ """
30
+
31
+ action: str # current action, e.g. "IMAGINE", "UPSCALE", "VARIATION"
32
+ prefix_content: str # prefix content, task description and process hint
33
+ task_id: str # task id
34
+ start_time: float # task start timestamp
35
+ timeout: int # task timeout in seconds
36
+ finished: bool # whether the task is finished
37
+ prompt: str # prompt for the task
38
+
39
+ def __init__(self, action, prefix_content, task_id, timeout=900):
40
+ self.action = action
41
+ self.prefix_content = prefix_content
42
+ self.task_id = task_id
43
+ self.start_time = time.time()
44
+ self.timeout = timeout
45
+ self.finished = False
46
+
47
+ def __init__(self, model_name, api_key, user_name=""):
48
+ super().__init__(api_key, user_name)
49
+ self.model_name = model_name
50
+ self.history = []
51
+ self.api_key = api_key
52
+ self.headers = {
53
+ "Content-Type": "application/json",
54
+ "mj-api-secret": f"{api_key}"
55
+ }
56
+ self.proxy_url = mj_proxy_api_base
57
+ self.command_splitter = "::"
58
+
59
+ if mj_temp_folder:
60
+ temp = "./tmp"
61
+ if user_name:
62
+ temp = os.path.join(temp, user_name)
63
+ if not os.path.exists(temp):
64
+ os.makedirs(temp)
65
+ self.temp_path = tempfile.mkdtemp(dir=temp)
66
+ logging.info("mj temp folder: " + self.temp_path)
67
+ else:
68
+ self.temp_path = None
69
+
70
+ def use_mj_self_proxy_url(self, img_url):
71
+ """
72
+ replace discord cdn url with mj self proxy url
73
+ """
74
+ return img_url.replace(
75
+ "https://cdn.discordapp.com/",
76
+ mj_discord_proxy_url and mj_discord_proxy_url or "https://cdn.discordapp.com/"
77
+ )
78
+
79
+ def split_image(self, image_url):
80
+ """
81
+ when enabling temp dir, split image into 4 parts
82
+ """
83
+ with retrieve_proxy():
84
+ image_bytes = requests.get(image_url).content
85
+ img = Image.open(io.BytesIO(image_bytes))
86
+ width, height = img.size
87
+ # calculate half width and height
88
+ half_width = width // 2
89
+ half_height = height // 2
90
+ # create coordinates (top-left x, top-left y, bottom-right x, bottom-right y)
91
+ coordinates = [(0, 0, half_width, half_height),
92
+ (half_width, 0, width, half_height),
93
+ (0, half_height, half_width, height),
94
+ (half_width, half_height, width, height)]
95
+
96
+ images = [img.crop(c) for c in coordinates]
97
+ return images
98
+
99
+ def auth_mj(self):
100
+ """
101
+ auth midjourney api
102
+ """
103
+ # TODO: check if secret is valid
104
+ return {'status': 'ok'}
105
+
106
+ def request_mj(self, path: str, action: str, data: str, retries=3):
107
+ """
108
+ request midjourney api
109
+ """
110
+ mj_proxy_url = self.proxy_url
111
+ if mj_proxy_url is None or not (mj_proxy_url.startswith("http://") or mj_proxy_url.startswith("https://")):
112
+ raise Exception('please set MIDJOURNEY_PROXY_API_BASE in ENV or in config.json')
113
+
114
+ auth_ = self.auth_mj()
115
+ if auth_.get('error'):
116
+ raise Exception('auth not set')
117
+
118
+ fetch_url = f"{mj_proxy_url}/{path}"
119
+ # logging.info(f"[MJ Proxy] {action} {fetch_url} params: {data}")
120
+
121
+ for _ in range(retries):
122
+ try:
123
+ with retrieve_proxy():
124
+ res = requests.request(method=action, url=fetch_url, headers=self.headers, data=data)
125
+ break
126
+ except Exception as e:
127
+ print(e)
128
+
129
+ if res.status_code != 200:
130
+ raise Exception(f'{res.status_code} - {res.content}')
131
+
132
+ return res
133
+
134
+ def fetch_status(self, fetch_data: FetchDataPack):
135
+ """
136
+ fetch status of current task
137
+ """
138
+ if fetch_data.start_time + fetch_data.timeout < time.time():
139
+ fetch_data.finished = True
140
+ return "任务超时,请检查 dc 输出。描述:" + fetch_data.prompt
141
+
142
+ time.sleep(3)
143
+ status_res = self.request_mj(f"task/{fetch_data.task_id}/fetch", "GET", '')
144
+ status_res_json = status_res.json()
145
+ if not (200 <= status_res.status_code < 300):
146
+ raise Exception("任务状态获取失败:" + status_res_json.get(
147
+ 'error') or status_res_json.get('description') or '未知错误')
148
+ else:
149
+ fetch_data.finished = False
150
+ if status_res_json['status'] == "SUCCESS":
151
+ content = status_res_json['imageUrl']
152
+ fetch_data.finished = True
153
+ elif status_res_json['status'] == "FAILED":
154
+ content = status_res_json['failReason'] or '未知原因'
155
+ fetch_data.finished = True
156
+ elif status_res_json['status'] == "NOT_START":
157
+ content = f'任务未开始,已等待 {time.time() - fetch_data.start_time:.2f} 秒'
158
+ elif status_res_json['status'] == "IN_PROGRESS":
159
+ content = '任务正在运行'
160
+ if status_res_json.get('progress'):
161
+ content += f",进度:{status_res_json['progress']}"
162
+ elif status_res_json['status'] == "SUBMITTED":
163
+ content = '任务已提交处理'
164
+ elif status_res_json['status'] == "FAILURE":
165
+ fetch_data.finished = True
166
+ return "任务处理失败,原因:" + status_res_json['failReason'] or '未知原因'
167
+ else:
168
+ content = status_res_json['status']
169
+ if fetch_data.finished:
170
+ img_url = self.use_mj_self_proxy_url(status_res_json['imageUrl'])
171
+ if fetch_data.action == "DESCRIBE":
172
+ return f"\n{status_res_json['prompt']}"
173
+ time_cost_str = f"\n\n{fetch_data.action} 花费时间:{time.time() - fetch_data.start_time:.2f} 秒"
174
+ upscale_str = ""
175
+ variation_str = ""
176
+ if fetch_data.action in ["IMAGINE", "UPSCALE", "VARIATION"]:
177
+ upscale = [f'/mj UPSCALE{self.command_splitter}{i+1}{self.command_splitter}{fetch_data.task_id}'
178
+ for i in range(4)]
179
+ upscale_str = '\n放大图片:\n\n' + '\n\n'.join(upscale)
180
+ variation = [f'/mj VARIATION{self.command_splitter}{i+1}{self.command_splitter}{fetch_data.task_id}'
181
+ for i in range(4)]
182
+ variation_str = '\n图片变体:\n\n' + '\n\n'.join(variation)
183
+ if self.temp_path and fetch_data.action in ["IMAGINE", "VARIATION"]:
184
+ try:
185
+ images = self.split_image(img_url)
186
+ # save images to temp path
187
+ for i in range(4):
188
+ images[i].save(pathlib.Path(self.temp_path) / f"{fetch_data.task_id}_{i}.png")
189
+ img_str = '\n'.join(
190
+ [f"![{fetch_data.task_id}](/file={self.temp_path}/{fetch_data.task_id}_{i}.png)"
191
+ for i in range(4)])
192
+ return fetch_data.prefix_content + f"{time_cost_str}\n\n{img_str}{upscale_str}{variation_str}"
193
+ except Exception as e:
194
+ logging.error(e)
195
+ return fetch_data.prefix_content + \
196
+ f"{time_cost_str}[![{fetch_data.task_id}]({img_url})]({img_url}){upscale_str}{variation_str}"
197
+ else:
198
+ content = f"**任务状态:** [{(datetime.now()).strftime('%Y-%m-%d %H:%M:%S')}] - {content}"
199
+ content += f"\n\n花费时间:{time.time() - fetch_data.start_time:.2f} 秒"
200
+ if status_res_json['status'] == 'IN_PROGRESS' and status_res_json.get('imageUrl'):
201
+ img_url = status_res_json.get('imageUrl')
202
+ return f"{content}\n[![{fetch_data.task_id}]({img_url})]({img_url})"
203
+ return content
204
+ return None
205
+
206
+ def handle_file_upload(self, files, chatbot, language):
207
+ """
208
+ handle file upload
209
+ """
210
+ if files:
211
+ for file in files:
212
+ if file.name:
213
+ logging.info(f"尝试读取图像: {file.name}")
214
+ self.try_read_image(file.name)
215
+ if self.image_path is not None:
216
+ chatbot = chatbot + [((self.image_path,), None)]
217
+ if self.image_bytes is not None:
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']
228
+ answer = self.get_help()
229
+
230
+ if not content.lower().startswith("/mj"):
231
+ return answer, len(content)
232
+
233
+ prompt = content[3:].strip()
234
+ action = "IMAGINE"
235
+ first_split_index = prompt.find(self.command_splitter)
236
+ if first_split_index > 0:
237
+ action = prompt[:first_split_index]
238
+ if action not in ["IMAGINE", "DESCRIBE", "UPSCALE",
239
+ # "VARIATION", "BLEND", "REROLL"
240
+ ]:
241
+ raise Exception("任务提交失败:未知的任务类型")
242
+ else:
243
+ action_index = None
244
+ action_use_task_id = None
245
+ if action in ["VARIATION", "UPSCALE", "REROLL"]:
246
+ action_index = int(prompt[first_split_index + 2:first_split_index + 3])
247
+ action_use_task_id = prompt[first_split_index + 5:]
248
+
249
+ try:
250
+ res = None
251
+ if action == "IMAGINE":
252
+ data = {
253
+ "prompt": prompt
254
+ }
255
+ if self.image_bytes is not None:
256
+ data["base64"] = 'data:image/png;base64,' + self.image_bytes
257
+ res = self.request_mj("submit/imagine", "POST",
258
+ json.dumps(data))
259
+ elif action == "DESCRIBE":
260
+ res = self.request_mj("submit/describe", "POST",
261
+ json.dumps({"base64": 'data:image/png;base64,' + self.image_bytes}))
262
+ elif action == "BLEND":
263
+ res = self.request_mj("submit/blend", "POST", json.dumps(
264
+ {"base64Array": [self.image_bytes, self.image_bytes]}))
265
+ elif action in ["UPSCALE", "VARIATION", "REROLL"]:
266
+ res = self.request_mj(
267
+ "submit/change", "POST",
268
+ json.dumps({"action": action, "index": action_index, "taskId": action_use_task_id}))
269
+ res_json = res.json()
270
+ if not (200 <= res.status_code < 300) or (res_json['code'] not in [1, 22]):
271
+ answer = "任务提交失败:" + res_json.get('error', res_json.get('description', '未知错误'))
272
+ else:
273
+ task_id = res_json['result']
274
+ prefix_content = f"**画面描述:** {prompt}\n**任务ID:** {task_id}\n"
275
+
276
+ fetch_data = Midjourney_Client.FetchDataPack(
277
+ action=action,
278
+ prefix_content=prefix_content,
279
+ task_id=task_id,
280
+ )
281
+ fetch_data.prompt = prompt
282
+ while not fetch_data.finished:
283
+ answer = self.fetch_status(fetch_data)
284
+ except Exception as e:
285
+ logging.error("submit failed", e)
286
+ answer = "任务提交错误:" + str(e.args[0]) if e.args else '未知错误'
287
+
288
+ return answer, tiktoken.get_encoding("cl100k_base").encode(content)
289
+
290
+ def get_answer_stream_iter(self):
291
+ content = self.history[-1]['content']
292
+ answer = self.get_help()
293
+
294
+ if not content.lower().startswith("/mj"):
295
+ yield answer
296
+ return
297
+
298
+ prompt = content[3:].strip()
299
+ action = "IMAGINE"
300
+ first_split_index = prompt.find(self.command_splitter)
301
+ if first_split_index > 0:
302
+ action = prompt[:first_split_index]
303
+ if action not in ["IMAGINE", "DESCRIBE", "UPSCALE",
304
+ "VARIATION", "BLEND", "REROLL"
305
+ ]:
306
+ yield "任务提交失败:未知的任务类型"
307
+ return
308
+
309
+ action_index = None
310
+ action_use_task_id = None
311
+ if action in ["VARIATION", "UPSCALE", "REROLL"]:
312
+ action_index = int(prompt[first_split_index + 2:first_split_index + 3])
313
+ action_use_task_id = prompt[first_split_index + 5:]
314
+
315
+ try:
316
+ res = None
317
+ if action == "IMAGINE":
318
+ data = {
319
+ "prompt": prompt
320
+ }
321
+ if self.image_bytes is not None:
322
+ data["base64"] = 'data:image/png;base64,' + self.image_bytes
323
+ res = self.request_mj("submit/imagine", "POST",
324
+ json.dumps(data))
325
+ elif action == "DESCRIBE":
326
+ res = self.request_mj("submit/describe", "POST", json.dumps(
327
+ {"base64": 'data:image/png;base64,' + self.image_bytes}))
328
+ elif action == "BLEND":
329
+ res = self.request_mj("submit/blend", "POST", json.dumps(
330
+ {"base64Array": [self.image_bytes, self.image_bytes]}))
331
+ elif action in ["UPSCALE", "VARIATION", "REROLL"]:
332
+ res = self.request_mj(
333
+ "submit/change", "POST",
334
+ json.dumps({"action": action, "index": action_index, "taskId": action_use_task_id}))
335
+ res_json = res.json()
336
+ if not (200 <= res.status_code < 300) or (res_json['code'] not in [1, 22]):
337
+ yield "任务提交失败:" + res_json.get('error', res_json.get('description', '未知错误'))
338
+ else:
339
+ task_id = res_json['result']
340
+ prefix_content = f"**画面描述:** {prompt}\n**任务ID:** {task_id}\n"
341
+ content = f"[{(datetime.now()).strftime('%Y-%m-%d %H:%M:%S')}] - 任务提交成功:" + \
342
+ res_json.get('description') or '请稍等片刻'
343
+ yield content
344
+
345
+ fetch_data = Midjourney_Client.FetchDataPack(
346
+ action=action,
347
+ prefix_content=prefix_content,
348
+ task_id=task_id,
349
+ )
350
+ while not fetch_data.finished:
351
+ yield self.fetch_status(fetch_data)
352
+ except Exception as e:
353
+ logging.error('submit failed', e)
354
+ yield "任务提交错误:" + str(e.args[0]) if e.args else '未知错误'
355
+
356
+ def get_help(self):
357
+ return """```
358
+ 【绘图帮助】
359
+ 所有命令都需要以 /mj 开头,如:/mj a dog
360
+ IMAGINE - 绘图,可以省略该命令,后面跟上绘图内容
361
+ /mj a dog
362
+ /mj IMAGINE::a cat
363
+ DESCRIBE - 描述图片,需要在右下角上传需要描述的图片内容
364
+ /mj DESCRIBE::
365
+ UPSCALE - 确认后放大图片,第一个数值为需要放大的图片(1~4),第二参数为任务ID
366
+ /mj UPSCALE::1::123456789
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
374
+ 长宽比 --aspect/--ar
375
+ --ar 1:2
376
+ --ar 16:9
377
+ 负面tag --no
378
+ --no plants
379
+ --no hands
380
+ 随机种子 --seed
381
+ --seed 1
382
+ 生成动漫风格(NijiJourney) --niji
383
+ --niji
384
+ ```
385
+ """
modules/models/models.py CHANGED
@@ -24,7 +24,7 @@ from ..presets import *
24
  from ..index_func import *
25
  from ..utils import *
26
  from .. import shared
27
- from ..config import retrieve_proxy, usage_limit
28
  from modules import config
29
  from .base_model import BaseLLMModel, ModelType
30
 
@@ -87,21 +87,23 @@ class OpenAIClient(BaseLLMModel):
87
  try:
88
  usage_data = self._get_billing_data(usage_url)
89
  except Exception as e:
90
- logging.error(f"获取API使用情况失败:" + str(e))
 
 
 
 
91
  return i18n("**获取API使用情况失败**")
92
  # rounded_usage = "{:.5f}".format(usage_data["total_usage"] / 100)
93
  rounded_usage = round(usage_data["total_usage"] / 100, 5)
94
  usage_percent = round(usage_data["total_usage"] / usage_limit, 2)
 
95
  # return i18n("**本月使用金额** ") + f"\u3000 ${rounded_usage}"
96
- return """\
97
- <b>""" + i18n("本月使用金额") + f"""</b>
98
- <div class="progress-bar">
99
- <div class="progress" style="width: {usage_percent}%;">
100
- <span class="progress-text">{usage_percent}%</span>
101
- </div>
102
- </div>
103
- <div style="display: flex; justify-content: space-between;"><span>${rounded_usage}</span><span>${usage_limit}</span></div>
104
- """
105
  except requests.exceptions.ConnectTimeout:
106
  status_text = (
107
  STANDARD_ERROR_MSG + CONNECTION_TIMEOUT_MSG + ERROR_RETRIEVE_MSG
@@ -161,7 +163,7 @@ class OpenAIClient(BaseLLMModel):
161
 
162
  # 如果有自定义的api-host,使用自定义host发送请求,否则使用默认设置发送请求
163
  if shared.state.completion_url != COMPLETION_URL:
164
- logging.info(f"使用自定义API URL: {shared.state.completion_url}")
165
 
166
  with retrieve_proxy():
167
  try:
@@ -179,9 +181,10 @@ class OpenAIClient(BaseLLMModel):
179
  def _refresh_header(self):
180
  self.headers = {
181
  "Content-Type": "application/json",
182
- "Authorization": f"Bearer {self.api_key}",
183
  }
184
 
 
185
  def _get_billing_data(self, billing_url):
186
  with retrieve_proxy():
187
  response = requests.get(
@@ -206,7 +209,7 @@ class OpenAIClient(BaseLLMModel):
206
  chunk_length = len(chunk)
207
  try:
208
  chunk = json.loads(chunk[6:])
209
- except json.JSONDecodeError:
210
  print(i18n("JSON解析错误,收到的内容: ") + f"{chunk}")
211
  error_msg += chunk
212
  continue
@@ -560,6 +563,7 @@ def get_model(
560
  try:
561
  if model_type == ModelType.OpenAI:
562
  logging.info(f"正在加载OpenAI模型: {model_name}")
 
563
  model = OpenAIClient(
564
  model_name=model_name,
565
  api_key=access_key,
@@ -610,16 +614,29 @@ def get_model(
610
  elif model_type == ModelType.ChuanhuAgent:
611
  from .ChuanhuAgent import ChuanhuAgent_Client
612
  model = ChuanhuAgent_Client(model_name, access_key, user_name=user_name)
 
 
 
 
 
 
 
 
 
 
 
613
  elif model_type == ModelType.Unknown:
614
  raise ValueError(f"未知模型: {model_name}")
615
  logging.info(msg)
616
  except Exception as e:
617
- logging.error(e)
 
618
  msg = f"{STANDARD_ERROR_MSG}: {e}"
 
619
  if dont_change_lora_selector:
620
- return model, msg, chatbot
621
  else:
622
- return model, msg, chatbot, gr.Dropdown.update(choices=lora_choices, visible=lora_selector_visibility)
623
 
624
 
625
  if __name__ == "__main__":
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
 
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
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:
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(
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
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,
569
  api_key=access_key,
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 .Google_PaLM import Google_PaLM_Client
619
+ access_key = os.environ.get("GOOGLE_PALM_API_KEY", access_key)
620
+ model = Google_PaLM_Client(model_name, access_key, user_name=user_name)
621
+ elif model_type == ModelType.LangchainChat:
622
+ from .azure import Azure_OpenAI_Client
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(model_name, mj_proxy_api_secret, user_name=user_name)
628
  elif model_type == ModelType.Unknown:
629
  raise ValueError(f"未知模型: {model_name}")
630
  logging.info(msg)
631
  except Exception as e:
632
+ import traceback
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:
639
+ return model, msg, chatbot, gr.Dropdown.update(choices=lora_choices, visible=lora_selector_visibility), access_key, presudo_key
640
 
641
 
642
  if __name__ == "__main__":
modules/overwrites.py CHANGED
@@ -71,23 +71,36 @@ def postprocess_chat_messages(
71
  else:
72
  raise ValueError(f"Invalid message for Chatbot component: {chat_message}")
73
 
74
- with open("./assets/custom.js", "r", encoding="utf-8") as f, \
75
- open("./assets/external-scripts.js", "r", encoding="utf-8") as f1:
76
- customJS = f.read()
77
- externalScripts = f1.read()
78
-
79
-
80
- def reload_javascript():
81
- print("Reloading javascript...")
82
- js = f'<script>{customJS}</script><script async>{externalScripts}</script>'
83
- # if render_latex:
84
- # js += """\"""
85
- def template_response(*args, **kwargs):
86
- res = GradioTemplateResponseOriginal(*args, **kwargs)
87
- res.body = res.body.replace(b'</html>', f'{js}</html>'.encode("utf8"))
88
- res.init_headers()
89
- return res
90
-
91
- gr.routes.templates.TemplateResponse = template_response
92
-
93
- GradioTemplateResponseOriginal = gr.routes.templates.TemplateResponse
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  else:
72
  raise ValueError(f"Invalid message for Chatbot component: {chat_message}")
73
 
74
+
75
+
76
+ def add_classes_to_gradio_component(comp):
77
+ """
78
+ this adds gradio-* to the component for css styling (ie gradio-button to gr.Button), as well as some others
79
+ code from stable-diffusion-webui <AUTOMATIC1111/stable-diffusion-webui>
80
+ """
81
+
82
+ comp.elem_classes = [f"gradio-{comp.get_block_name()}", *(comp.elem_classes or [])]
83
+
84
+ if getattr(comp, 'multiselect', False):
85
+ comp.elem_classes.append('multiselect')
86
+
87
+
88
+ def IOComponent_init(self, *args, **kwargs):
89
+ res = original_IOComponent_init(self, *args, **kwargs)
90
+ add_classes_to_gradio_component(self)
91
+
92
+ return res
93
+
94
+ original_IOComponent_init = gr.components.IOComponent.__init__
95
+ gr.components.IOComponent.__init__ = IOComponent_init
96
+
97
+
98
+ def BlockContext_init(self, *args, **kwargs):
99
+ res = original_BlockContext_init(self, *args, **kwargs)
100
+ add_classes_to_gradio_component(self)
101
+
102
+ return res
103
+
104
+ original_BlockContext_init = gr.blocks.BlockContext.__init__
105
+ gr.blocks.BlockContext.__init__ = BlockContext_init
106
+
modules/presets.py CHANGED
@@ -60,19 +60,24 @@ ONLINE_MODELS = [
60
  "gpt-4-32k-0613",
61
  "川虎助理",
62
  "川虎助理 Pro",
 
63
  "xmchat",
 
64
  "yuanai-1.0-base_10B",
65
  "yuanai-1.0-translate",
66
  "yuanai-1.0-dialog",
67
  "yuanai-1.0-rhythm_poems",
68
  "minimax-abab4-chat",
69
  "minimax-abab5-chat",
 
70
  ]
71
 
72
  LOCAL_MODELS = [
73
  "chatglm-6b",
74
  "chatglm-6b-int4",
75
- "chatglm-6b-int4-qe",
 
 
76
  "StableLM",
77
  "MOSS",
78
  "llama-7b-hf",
@@ -121,6 +126,7 @@ REPLY_LANGUAGES = [
121
  "Español",
122
  "Français",
123
  "Deutsch",
 
124
  "跟随问题语言(不稳定)"
125
  ]
126
 
@@ -170,6 +176,8 @@ SUMMARIZE_PROMPT = """Write a concise summary of the following:
170
  CONCISE SUMMARY IN 中文:"""
171
 
172
  ALREADY_CONVERTED_MARK = "<!-- ALREADY CONVERTED BY PARSER. -->"
 
 
173
 
174
  small_and_beautiful_theme = gr.themes.Soft(
175
  primary_hue=gr.themes.Color(
@@ -222,7 +230,7 @@ small_and_beautiful_theme = gr.themes.Soft(
222
  # button_primary_background_fill_hover="*primary_400",
223
  # button_primary_border_color="*primary_500",
224
  button_primary_border_color_dark="*primary_600",
225
- button_primary_text_color="wihte",
226
  button_primary_text_color_dark="white",
227
  button_secondary_background_fill="*neutral_100",
228
  button_secondary_background_fill_hover="*neutral_50",
60
  "gpt-4-32k-0613",
61
  "川虎助理",
62
  "川虎助理 Pro",
63
+ "GooglePaLM",
64
  "xmchat",
65
+ "Azure OpenAI",
66
  "yuanai-1.0-base_10B",
67
  "yuanai-1.0-translate",
68
  "yuanai-1.0-dialog",
69
  "yuanai-1.0-rhythm_poems",
70
  "minimax-abab4-chat",
71
  "minimax-abab5-chat",
72
+ "midjourney"
73
  ]
74
 
75
  LOCAL_MODELS = [
76
  "chatglm-6b",
77
  "chatglm-6b-int4",
78
+ "chatglm-6b-int4-ge",
79
+ "chatglm2-6b",
80
+ "chatglm2-6b-int4",
81
  "StableLM",
82
  "MOSS",
83
  "llama-7b-hf",
126
  "Español",
127
  "Français",
128
  "Deutsch",
129
+ "한국어",
130
  "跟随问题语言(不稳定)"
131
  ]
132
 
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 -->"
181
 
182
  small_and_beautiful_theme = gr.themes.Soft(
183
  primary_hue=gr.themes.Color(
230
  # button_primary_background_fill_hover="*primary_400",
231
  # button_primary_border_color="*primary_500",
232
  button_primary_border_color_dark="*primary_600",
233
+ button_primary_text_color="white",
234
  button_primary_text_color_dark="white",
235
  button_secondary_background_fill="*neutral_100",
236
  button_secondary_background_fill_hover="*neutral_50",
modules/repo.py ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding:utf-8 -*-
2
+ import os
3
+ import sys
4
+ import subprocess
5
+ 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('PIP', "pip")
15
+ git = os.environ.get('GIT', "git")
16
+
17
+ # Pypi index url
18
+ index_url = os.environ.get('INDEX_URL', "")
19
+
20
+ # Whether to default to printing command output
21
+ default_command_live = True
22
+
23
+
24
+ def run(command, desc=None, errdesc=None, custom_env=None, live: bool = default_command_live) -> str:
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": 'utf8',
32
+ "errors": 'ignore',
33
+ }
34
+
35
+ if not live:
36
+ run_kwargs["stdout"] = run_kwargs["stderr"] = subprocess.PIPE
37
+
38
+ result = subprocess.run(**run_kwargs)
39
+ if result.returncode != 0:
40
+ error_bits = [
41
+ f"{errdesc or 'Error running command'}.",
42
+ f"Command: {command}",
43
+ f"Error code: {result.returncode}",
44
+ ]
45
+ if result.stdout:
46
+ error_bits.append(f"stdout: {result.stdout}")
47
+ if result.stderr:
48
+ error_bits.append(f"stderr: {result.stderr}")
49
+ raise RuntimeError("\n".join(error_bits))
50
+
51
+ return (result.stdout or "")
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' --index-url {index_url}' if index_url != '' else ''
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([git, "rev-parse", "HEAD"], shell=False, encoding='utf8').strip()
71
+ except Exception:
72
+ return "<none>"
73
+
74
+ def commit_html():
75
+ commit = commit_hash()
76
+ if commit != "<none>":
77
+ short_commit = commit[0:7]
78
+ commit_info = f'<a style="text-decoration:none;color:inherit" href="https://github.com/GaiZhenbiao/ChuanhuChatGPT/commit/{short_commit}">{short_commit}</a>'
79
+ else:
80
+ commit_info = "unknown \U0001F615"
81
+ return commit_info
82
+
83
+ @lru_cache()
84
+ def tag_html():
85
+ try:
86
+ latest_tag = run(f"{git} describe --tags --abbrev=0", live=False).strip()
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>"
94
+
95
+ if tag == "<none>":
96
+ tag_info = "unknown \U0001F615"
97
+ elif tag == "<edited>":
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()
112
+ return f"""
113
+ Python: <span title="{sys.version}">{python_version}</span>
114
+  • 
115
+ Gradio: {gr.__version__}
116
+  • 
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
+ commit_time = subprocess.check_output(f"TZ=UTC {git} log -1 --format=%cd --date='format-local:%Y-%m-%dT%H:%M:%SZ'", shell=True, encoding='utf8').strip()
123
+ # commit_time = run(f"TZ=UTC {git} log -1 --format=%cd --date='format-local:%Y-%m-%dT%H:%M:%SZ'").strip()
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([git, "rev-parse", "--abbrev-ref", "HEAD"], shell=False, encoding='utf8').strip()
134
+ except Exception:
135
+ branch = "<none>"
136
+ return branch
137
+
138
+
139
+ def get_latest_release():
140
+ try:
141
+ import requests
142
+ release = requests.get("https://api.github.com/repos/GaiZhenbiao/ChuanhuChatGPT/releases/latest").json()
143
+ tag = release["tag_name"]
144
+ release_note = release["body"]
145
+ need_pip = release_note.find("requirements reinstall needed") != -1
146
+ except Exception:
147
+ tag = "<none>"
148
+ release_note = ""
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
+ tags = requests.get("https://api.github.com/repos/GaiZhenbiao/ChuanhuChatGPT/tags").json()
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 subprocess.check_output([git, "diff-index", "--quiet", "HEAD", "--"], shell=False, encoding='utf8').strip() != ""
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:
170
+ latest_release = get_latest_release()
171
+ latest_release_tag = latest_release["tag"]
172
+ latest_release_hash = get_tag_commit_hash(latest_release_tag)
173
+ need_pip = latest_release["need_pip"]
174
+ need_stash = repo_need_stash()
175
+
176
+ timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
177
+ current_branch = get_current_branch()
178
+ updater_branch = f'tmp_{timestamp}'
179
+ backup_branch = f'backup_{timestamp}'
180
+ track_repo = "https://github.com/GaiZhenbiao/ChuanhuChatGPT.git"
181
+ try:
182
+ try:
183
+ run(f"{git} fetch {track_repo}", desc="[Updater] Fetching from github...", live=False)
184
+ except Exception:
185
+ logging.error(f"Update failed in fetching, check your network connection")
186
+ return "failed"
187
+
188
+ run(f'{git} stash push --include-untracked -m "updater-{timestamp}"',
189
+ desc=f'[Updater] Restoring you local changes on stash updater-{timestamp}', live=False) if need_stash else None
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(f"{git} reset --hard {latest_release_hash}", desc=f'[Updater] Checking out {latest_release_tag}...', live=False)
195
+ run(f"{git} checkout {current_branch}", live=False)
196
+
197
+ try:
198
+ run(f"{git} merge --no-edit {updater_branch} -q", desc=f"[Updater] Trying to apply latest update on version {latest_release_tag}...")
199
+ except Exception:
200
+ logging.error(f"Update failed in merging")
201
+ try:
202
+ run(f"{git} merge --abort", desc="[Updater] Conflict detected, canceling update...")
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(f"Update failed, but your file was safely reset to the state before the update.")
208
+ return "failed"
209
+ except Exception as e:
210
+ logging.error(f"!!!Update failed in resetting, try to reset your files manually. {e}")
211
+ return "failed"
212
+
213
+ if need_stash:
214
+ try:
215
+ run(f"{git} stash apply", desc="[Updater] Trying to restore your local modifications...", live=False)
216
+ except Exception:
217
+ run(f"{git} reset --hard {backup_branch}", desc="[Updater] Conflict detected, canceling update...", live=False)
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(f"Update failed in applying your local changes, but your file was safely reset to the state before the update.")
222
+ return "failed"
223
+ run(f"{git} stash drop", live=False)
224
+
225
+ run(f"{git} branch -D -f {updater_branch}", live=False)
226
+ run(f"{git} branch -D -f {backup_branch}", live=False)
227
+ except Exception as e:
228
+ logging.error(f"Update failed: {e}")
229
+ return "failed"
230
+ if need_pip:
231
+ try:
232
+ run_pip(f"install -r requirements.txt", pref="[Updater]", desc="requirements", live=False)
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"
modules/shared.py CHANGED
@@ -62,3 +62,4 @@ state = State()
62
 
63
  modules_path = os.path.dirname(os.path.realpath(__file__))
64
  chuanhu_path = os.path.dirname(modules_path)
 
62
 
63
  modules_path = os.path.dirname(os.path.realpath(__file__))
64
  chuanhu_path = os.path.dirname(modules_path)
65
+ assets_path = os.path.join(chuanhu_path, "web_assets")
modules/train_func.py ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ import traceback
4
+
5
+ import openai
6
+ import gradio as gr
7
+ import ujson as json
8
+ import commentjson
9
+ import openpyxl
10
+
11
+ import modules.presets as presets
12
+ from modules.utils import get_file_hash, count_token
13
+ from modules.presets import i18n
14
+
15
+ def excel_to_jsonl(filepath, preview=False):
16
+ # 打开Excel文件
17
+ workbook = openpyxl.load_workbook(filepath)
18
+
19
+ # 获取第一个工作表
20
+ sheet = workbook.active
21
+
22
+ # 获取所有行数据
23
+ data = []
24
+ for row in sheet.iter_rows(values_only=True):
25
+ data.append(row)
26
+
27
+ # 构建字典列表
28
+ headers = data[0]
29
+ jsonl = []
30
+ for row in data[1:]:
31
+ row_data = dict(zip(headers, row))
32
+ if any(row_data.values()):
33
+ jsonl.append(row_data)
34
+ formatted_jsonl = []
35
+ for i in jsonl:
36
+ if "提问" in i and "答案" in i:
37
+ if "系统" in i :
38
+ formatted_jsonl.append({
39
+ "messages":[
40
+ {"role": "system", "content": i["系统"]},
41
+ {"role": "user", "content": i["提问"]},
42
+ {"role": "assistant", "content": i["答案"]}
43
+ ]
44
+ })
45
+ else:
46
+ formatted_jsonl.append({
47
+ "messages":[
48
+ {"role": "user", "content": i["提问"]},
49
+ {"role": "assistant", "content": i["答案"]}
50
+ ]
51
+ })
52
+ else:
53
+ logging.warning(f"跳过一行数据,因为没有找到提问和答案: {i}")
54
+ return formatted_jsonl
55
+
56
+ def jsonl_save_to_disk(jsonl, filepath):
57
+ file_hash = get_file_hash(file_paths = [filepath])
58
+ os.makedirs("files", exist_ok=True)
59
+ save_path = f"files/{file_hash}.jsonl"
60
+ with open(save_path, "w") as f:
61
+ f.write("\n".join([json.dumps(i, ensure_ascii=False) for i in jsonl]))
62
+ return save_path
63
+
64
+ def estimate_cost(ds):
65
+ dialogues = []
66
+ for l in ds:
67
+ for m in l["messages"]:
68
+ dialogues.append(m["content"])
69
+ dialogues = "\n".join(dialogues)
70
+ tokens = count_token(dialogues)
71
+ return f"Token 数约为 {tokens},预估每轮(epoch)费用约为 {tokens / 1000 * 0.008} 美元。"
72
+
73
+
74
+ def handle_dataset_selection(file_src):
75
+ logging.info(f"Loading dataset {file_src.name}...")
76
+ preview = ""
77
+ if file_src.name.endswith(".jsonl"):
78
+ with open(file_src.name, "r") as f:
79
+ ds = [json.loads(l) for l in f.readlines()]
80
+ else:
81
+ ds = excel_to_jsonl(file_src.name)
82
+ preview = ds[0]
83
+
84
+ return preview, gr.update(interactive=True), estimate_cost(ds)
85
+
86
+ def upload_to_openai(file_src):
87
+ openai.api_key = os.getenv("OPENAI_API_KEY")
88
+ dspath = file_src.name
89
+ msg = ""
90
+ logging.info(f"Uploading dataset {dspath}...")
91
+ if dspath.endswith(".xlsx"):
92
+ jsonl = excel_to_jsonl(dspath)
93
+ dspath = jsonl_save_to_disk(jsonl, dspath)
94
+ try:
95
+ uploaded = openai.File.create(
96
+ file=open(dspath, "rb"),
97
+ purpose='fine-tune'
98
+ )
99
+ return uploaded.id, f"上传成功"
100
+ except Exception as e:
101
+ traceback.print_exc()
102
+ return "", f"上传失败,原因:{ e }"
103
+
104
+ def build_event_description(id, status, trained_tokens, name=i18n("暂时未知")):
105
+ # convert to markdown
106
+ return f"""
107
+ #### 训练任务 {id}
108
+
109
+ 模型名称:{name}
110
+
111
+ 状态:{status}
112
+
113
+ 已经训练了 {trained_tokens} 个token
114
+ """
115
+
116
+ def start_training(file_id, suffix, epochs):
117
+ openai.api_key = os.getenv("OPENAI_API_KEY")
118
+ try:
119
+ job = openai.FineTuningJob.create(training_file=file_id, model="gpt-3.5-turbo", suffix=suffix, hyperparameters={"n_epochs": epochs})
120
+ return build_event_description(job.id, job.status, job.trained_tokens)
121
+ except Exception as e:
122
+ traceback.print_exc()
123
+ if "is not ready" in str(e):
124
+ return "训练出错,因为文件还没准备好。OpenAI 需要一点时间准备文件,过几分钟再来试试。"
125
+ return f"训练失败,原因:{ e }"
126
+
127
+ def get_training_status():
128
+ openai.api_key = os.getenv("OPENAI_API_KEY")
129
+ active_jobs = [build_event_description(job["id"], job["status"], job["trained_tokens"], job["fine_tuned_model"]) for job in openai.FineTuningJob.list(limit=10)["data"] if job["status"] != "cancelled"]
130
+ return "\n\n".join(active_jobs), gr.update(interactive=True) if len(active_jobs) > 0 else gr.update(interactive=False)
131
+
132
+ def handle_dataset_clear():
133
+ return gr.update(value=None), gr.update(interactive=False)
134
+
135
+ def add_to_models():
136
+ openai.api_key = os.getenv("OPENAI_API_KEY")
137
+ succeeded_jobs = [job for job in openai.FineTuningJob.list()["data"] if job["status"] == "succeeded"]
138
+ extra_models = [job["fine_tuned_model"] for job in succeeded_jobs]
139
+ for i in extra_models:
140
+ if i not in presets.MODELS:
141
+ presets.MODELS.append(i)
142
+
143
+ with open('config.json', 'r') as f:
144
+ data = commentjson.load(f)
145
+ if 'extra_models' in data:
146
+ for i in extra_models:
147
+ if i not in data['extra_models']:
148
+ data['extra_models'].append(i)
149
+ else:
150
+ data['extra_models'] = extra_models
151
+ with open('config.json', 'w') as f:
152
+ commentjson.dump(data, f, indent=4)
153
+
154
+ return gr.update(choices=presets.MODELS), f"成功添加了 {len(succeeded_jobs)} 个模型。"
155
+
156
+ def cancel_all_jobs():
157
+ openai.api_key = os.getenv("OPENAI_API_KEY")
158
+ jobs = [job for job in openai.FineTuningJob.list()["data"] if job["status"] not in ["cancelled", "succeeded"]]
159
+ for job in jobs:
160
+ openai.FineTuningJob.cancel(job["id"])
161
+ return f"成功取消了 {len(jobs)} 个训练任务。"
modules/utils.py CHANGED
@@ -2,16 +2,14 @@
2
  from __future__ import annotations
3
  from typing import TYPE_CHECKING, Any, Callable, Dict, List, Tuple, Type
4
  import logging
5
- import json
6
  import os
7
  import datetime
8
- import hashlib
9
  import csv
10
  import requests
11
  import re
12
  import html
13
- import sys
14
- import subprocess
15
 
16
  import gradio as gr
17
  from pypinyin import lazy_pinyin
@@ -47,6 +45,9 @@ def set_key(current_model, *args):
47
  def load_chat_history(current_model, *args):
48
  return current_model.load_chat_history(*args)
49
 
 
 
 
50
  def interrupt(current_model, *args):
51
  return current_model.interrupt(*args)
52
 
@@ -125,9 +126,10 @@ def dislike(current_model, *args):
125
  return current_model.dislike(*args)
126
 
127
 
128
- def count_token(message):
129
  encoding = tiktoken.get_encoding("cl100k_base")
130
- input_str = f"role: {message['role']}, content: {message['content']}"
 
131
  length = len(encoding.encode(input_str))
132
  return length
133
 
@@ -202,6 +204,28 @@ def convert_mdtext(md_text): # deprecated
202
  output += ALREADY_CONVERTED_MARK
203
  return output
204
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  def convert_bot_before_marked(chat_message):
206
  """
207
  注意不能给输出加缩进, 否则会被marked解析成代码块
@@ -209,12 +233,13 @@ def convert_bot_before_marked(chat_message):
209
  if '<div class="md-message">' in chat_message:
210
  return chat_message
211
  else:
 
 
 
212
  code_block_pattern = re.compile(r"```(.*?)(?:```|$)", re.DOTALL)
213
  code_blocks = code_block_pattern.findall(chat_message)
214
  non_code_parts = code_block_pattern.split(chat_message)[::2]
215
  result = []
216
-
217
- raw = f'<div class="raw-message hideM">{escape_markdown(chat_message)}</div>'
218
  for non_code, code in zip(non_code_parts, code_blocks + [""]):
219
  if non_code.strip():
220
  result.append(non_code)
@@ -222,7 +247,7 @@ def convert_bot_before_marked(chat_message):
222
  code = f"\n```{code}\n```"
223
  result.append(code)
224
  result = "".join(result)
225
- md = f'<div class="md-message">{result}\n</div>'
226
  return raw + md
227
 
228
  def convert_user_before_marked(chat_message):
@@ -236,7 +261,7 @@ def escape_markdown(text):
236
  Escape Markdown special characters to HTML-safe equivalents.
237
  """
238
  escape_chars = {
239
- ' ': '&nbsp;',
240
  '_': '&#95;',
241
  '*': '&#42;',
242
  '[': '&#91;',
@@ -253,8 +278,12 @@ def escape_markdown(text):
253
  '`': '&#96;',
254
  '>': '&#62;',
255
  '<': '&#60;',
256
- '|': '&#124;'
 
 
 
257
  }
 
258
  return ''.join(escape_chars.get(c, c) for c in text)
259
 
260
 
@@ -508,55 +537,19 @@ def transfer_input(inputs):
508
  )
509
 
510
 
 
 
511
 
512
- def run(command, desc=None, errdesc=None, custom_env=None, live=False):
513
- if desc is not None:
514
- print(desc)
515
- if live:
516
- result = subprocess.run(command, shell=True, env=os.environ if custom_env is None else custom_env)
517
- if result.returncode != 0:
518
- raise RuntimeError(f"""{errdesc or 'Error running command'}.
519
- Command: {command}
520
- Error code: {result.returncode}""")
521
-
522
- return ""
523
- result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, env=os.environ if custom_env is None else custom_env)
524
- if result.returncode != 0:
525
- message = f"""{errdesc or 'Error running command'}.
526
- Command: {command}
527
- Error code: {result.returncode}
528
- stdout: {result.stdout.decode(encoding="utf8", errors="ignore") if len(result.stdout)>0 else '<empty>'}
529
- stderr: {result.stderr.decode(encoding="utf8", errors="ignore") if len(result.stderr)>0 else '<empty>'}
530
- """
531
- raise RuntimeError(message)
532
- return result.stdout.decode(encoding="utf8", errors="ignore")
533
-
534
- def versions_html():
535
- git = os.environ.get('GIT', "git")
536
- python_version = ".".join([str(x) for x in sys.version_info[0:3]])
537
- try:
538
- commit_hash = run(f"{git} rev-parse HEAD").strip()
539
- except Exception:
540
- commit_hash = "<none>"
541
- if commit_hash != "<none>":
542
- short_commit = commit_hash[0:7]
543
- commit_info = f"<a style=\"text-decoration:none;color:inherit\" href=\"https://github.com/GaiZhenbiao/ChuanhuChatGPT/commit/{short_commit}\">{short_commit}</a>"
544
  else:
545
- commit_info = "unknown \U0001F615"
546
- return f"""
547
- Python: <span title="{sys.version}">{python_version}</span>
548
-  • 
549
- Gradio: {gr.__version__}
550
-  • 
551
- <a style="text-decoration:none;color:inherit" href="https://github.com/GaiZhenbiao/ChuanhuChatGPT">ChuanhuChat</a>: {commit_info}
552
- """
553
-
554
- def get_html(filename):
555
- path = os.path.join(shared.chuanhu_path, "assets", "html", filename)
556
- if os.path.exists(path):
557
- with open(path, encoding="utf8") as file:
558
- return file.read()
559
- return ""
560
 
561
  def add_source_numbers(lst, source_name = "Source", use_source = True):
562
  if use_source:
@@ -654,3 +647,37 @@ def get_history_filepath(username):
654
 
655
  latest_file = os.path.join(dirname, latest_file)
656
  return latest_file
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  from __future__ import annotations
3
  from typing import TYPE_CHECKING, Any, Callable, Dict, List, Tuple, Type
4
  import logging
5
+ import commentjson as json
6
  import os
7
  import datetime
 
8
  import csv
9
  import requests
10
  import re
11
  import html
12
+ import hashlib
 
13
 
14
  import gradio as gr
15
  from pypinyin import lazy_pinyin
45
  def load_chat_history(current_model, *args):
46
  return current_model.load_chat_history(*args)
47
 
48
+ def delete_chat_history(current_model, *args):
49
+ return current_model.delete_chat_history(*args)
50
+
51
  def interrupt(current_model, *args):
52
  return current_model.interrupt(*args)
53
 
126
  return current_model.dislike(*args)
127
 
128
 
129
+ def count_token(input_str):
130
  encoding = tiktoken.get_encoding("cl100k_base")
131
+ if type(input_str) == dict:
132
+ input_str = f"role: {input_str['role']}, content: {input_str['content']}"
133
  length = len(encoding.encode(input_str))
134
  return length
135
 
204
  output += ALREADY_CONVERTED_MARK
205
  return output
206
 
207
+
208
+ def clip_rawtext(chat_message, need_escape=True):
209
+ # first, clip hr line
210
+ hr_pattern = r'\n\n<hr class="append-display no-in-raw" />(.*?)'
211
+ hr_match = re.search(hr_pattern, chat_message, re.DOTALL)
212
+ message_clipped = chat_message[:hr_match.start()] if hr_match else chat_message
213
+ # second, avoid agent-prefix being escaped
214
+ agent_prefix_pattern = r'<!-- S O PREFIX --><p class="agent-prefix">(.*?)<\/p><!-- E O PREFIX -->'
215
+ agent_matches = re.findall(agent_prefix_pattern, message_clipped)
216
+ final_message = ""
217
+ if agent_matches:
218
+ agent_parts = re.split(agent_prefix_pattern, message_clipped)
219
+ for i, part in enumerate(agent_parts):
220
+ if i % 2 == 0:
221
+ final_message += escape_markdown(part) if need_escape else part
222
+ else:
223
+ final_message += f'<!-- S O PREFIX --><p class="agent-prefix">{part}</p><!-- E O PREFIX -->'
224
+ else:
225
+ final_message = escape_markdown(message_clipped) if need_escape else message_clipped
226
+ return final_message
227
+
228
+
229
  def convert_bot_before_marked(chat_message):
230
  """
231
  注意不能给输出加缩进, 否则会被marked解析成代码块
233
  if '<div class="md-message">' in chat_message:
234
  return chat_message
235
  else:
236
+ raw = f'<div class="raw-message hideM"><pre>{clip_rawtext(chat_message)}</pre></div>'
237
+ # really_raw = f'{START_OF_OUTPUT_MARK}<div class="really-raw hideM">{clip_rawtext(chat_message, need_escape=False)}\n</div>{END_OF_OUTPUT_MARK}'
238
+
239
  code_block_pattern = re.compile(r"```(.*?)(?:```|$)", re.DOTALL)
240
  code_blocks = code_block_pattern.findall(chat_message)
241
  non_code_parts = code_block_pattern.split(chat_message)[::2]
242
  result = []
 
 
243
  for non_code, code in zip(non_code_parts, code_blocks + [""]):
244
  if non_code.strip():
245
  result.append(non_code)
247
  code = f"\n```{code}\n```"
248
  result.append(code)
249
  result = "".join(result)
250
+ md = f'<div class="md-message">\n\n{result}\n</div>'
251
  return raw + md
252
 
253
  def convert_user_before_marked(chat_message):
261
  Escape Markdown special characters to HTML-safe equivalents.
262
  """
263
  escape_chars = {
264
+ # ' ': '&nbsp;',
265
  '_': '&#95;',
266
  '*': '&#42;',
267
  '[': '&#91;',
278
  '`': '&#96;',
279
  '>': '&#62;',
280
  '<': '&#60;',
281
+ '|': '&#124;',
282
+ '$': '&#36;',
283
+ ':': '&#58;',
284
+ '\n': '<br>',
285
  }
286
+ text = text.replace(' ', '&nbsp;&nbsp;&nbsp;&nbsp;')
287
  return ''.join(escape_chars.get(c, c) for c in text)
288
 
289
 
537
  )
538
 
539
 
540
+ def update_chuanhu():
541
+ from .repo import background_update
542
 
543
+ print("[Updater] Trying to update...")
544
+ update_status = background_update()
545
+ if update_status == "success":
546
+ logging.info("Successfully updated, restart needed")
547
+ status = '<span id="update-status" class="hideK">success</span>'
548
+ return gr.Markdown.update(value=i18n("更新成功,请重启本程序")+status)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
549
  else:
550
+ status = '<span id="update-status" class="hideK">failure</span>'
551
+ return gr.Markdown.update(value=i18n("更新失败,请尝试[手动更新](https://github.com/GaiZhenbiao/ChuanhuChatGPT/wiki/使用教程#手动更新)")+status)
552
+
 
 
 
 
 
 
 
 
 
 
 
 
553
 
554
  def add_source_numbers(lst, source_name = "Source", use_source = True):
555
  if use_source:
647
 
648
  latest_file = os.path.join(dirname, latest_file)
649
  return latest_file
650
+
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: gpt-4 does not exist" in err_msg:
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")
658
+ return err_msg
659
+
660
+ def auth_from_conf(username, password):
661
+ try:
662
+ with open("config.json", encoding="utf-8") as f:
663
+ conf = json.load(f)
664
+ usernames, passwords = [i[0] for i in conf["users"]], [i[1] for i in conf["users"]]
665
+ if username in usernames:
666
+ if passwords[usernames.index(username)] == password:
667
+ return True
668
+ return False
669
+ except:
670
+ return False
671
+
672
+ def get_file_hash(file_src=None, file_paths=None):
673
+ if file_src:
674
+ file_paths = [x.name for x in file_src]
675
+ file_paths.sort(key=lambda x: os.path.basename(x))
676
+
677
+ md5_hash = hashlib.md5()
678
+ for file_path in file_paths:
679
+ with open(file_path, "rb") as f:
680
+ while chunk := f.read(8192):
681
+ md5_hash.update(chunk)
682
+
683
+ return md5_hash.hexdigest()
modules/webui.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from collections import namedtuple
3
+ import os
4
+ import gradio as gr
5
+
6
+ from . import shared
7
+
8
+ # with open("./assets/ChuanhuChat.js", "r", encoding="utf-8") as f, \
9
+ # open("./assets/external-scripts.js", "r", encoding="utf-8") as f1:
10
+ # customJS = f.read()
11
+ # externalScripts = f1.read()
12
+
13
+
14
+ def get_html(filename):
15
+ path = os.path.join(shared.chuanhu_path, "web_assets", "html", filename)
16
+ if os.path.exists(path):
17
+ with open(path, encoding="utf8") as file:
18
+ return file.read()
19
+ return ""
20
+
21
+ def webpath(fn):
22
+ if fn.startswith(shared.assets_path):
23
+ web_path = os.path.relpath(fn, shared.chuanhu_path).replace('\\', '/')
24
+ else:
25
+ web_path = os.path.abspath(fn)
26
+ return f'file={web_path}?{os.path.getmtime(fn)}'
27
+
28
+ ScriptFile = namedtuple("ScriptFile", ["basedir", "filename", "path"])
29
+
30
+ def javascript_html():
31
+ head = ""
32
+ for script in list_scripts("javascript", ".js"):
33
+ head += f'<script type="text/javascript" src="{webpath(script.path)}"></script>\n'
34
+ for script in list_scripts("javascript", ".mjs"):
35
+ head += f'<script type="module" src="{webpath(script.path)}"></script>\n'
36
+ return head
37
+
38
+ def css_html():
39
+ head = ""
40
+ for cssfile in list_scripts("stylesheet", ".css"):
41
+ head += f'<link rel="stylesheet" property="stylesheet" href="{webpath(cssfile.path)}">'
42
+ return head
43
+
44
+ def list_scripts(scriptdirname, extension):
45
+ scripts_list = []
46
+ scripts_dir = os.path.join(shared.chuanhu_path, "web_assets", scriptdirname)
47
+ if os.path.exists(scripts_dir):
48
+ for filename in sorted(os.listdir(scripts_dir)):
49
+ scripts_list.append(ScriptFile(shared.assets_path, filename, os.path.join(scripts_dir, filename)))
50
+ scripts_list = [x for x in scripts_list if os.path.splitext(x.path)[1].lower() == extension and os.path.isfile(x.path)]
51
+ return scripts_list
52
+
53
+
54
+ def reload_javascript():
55
+ js = javascript_html()
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
67
+
68
+ gr.routes.templates.TemplateResponse = template_response
69
+
70
+ GradioTemplateResponseOriginal = gr.routes.templates.TemplateResponse
readme/README_en.md CHANGED
@@ -6,7 +6,7 @@
6
  <h1 align="center">川虎 Chat 🐯 Chuanhu Chat</h1>
7
  <div align="center">
8
  <a href="https://github.com/GaiZhenBiao/ChuanhuChatGPT">
9
- <img src="https://user-images.githubusercontent.com/70903329/227087087-93b37d64-7dc3-4738-a518-c1cf05591c8a.png" alt="Logo" height="156">
10
  </a>
11
 
12
  <p align="center">
@@ -44,6 +44,23 @@
44
  </p>
45
  </div>
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  ## Usage Tips
48
 
49
  - To better control the ChatGPT, use System Prompt.
@@ -51,11 +68,11 @@
51
  - To try again if the response is unsatisfactory, use `🔄 Regenerate` button.
52
  - To start a new line in the input box, press <kbd>Shift</kbd> + <kbd>Enter</kbd> keys.
53
  - To quickly switch between input history, press <kbd>↑</kbd> and <kbd>↓</kbd> key in the input box.
54
- - To deploy the program onto a server, change the last line of the program to `demo.launch(server_name="0.0.0.0", server_port=<your port number>)`.
55
- - To get a public shared link, change the last line of the program to `demo.launch(share=True)`. Please be noted that the program must be running in order to be accessed via a public link.
56
  - To use it in Hugging Face Spaces: It is recommended to **Duplicate Space** and run the program in your own Space for a faster and more secure experience.
57
 
58
- ## Installation
59
 
60
  ```shell
61
  git clone https://github.com/GaiZhenbiao/ChuanhuChatGPT.git
@@ -87,10 +104,6 @@ When you encounter problems, you should try manually pulling the latest changes
87
  ```
88
  pip install -r requirements.txt
89
  ```
90
- 3. Update Gradio
91
- ```
92
- pip install gradio --upgrade --force-reinstall
93
- ```
94
 
95
  Generally, you can solve most problems by following these steps.
96
 
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">
44
  </p>
45
  </div>
46
 
47
+ ## Supported LLM Models
48
+
49
+ **LLM models via API**:
50
+
51
+ - [ChatGPT](https://chat.openai.com) ([GPT-4](https://openai.com/product/gpt-4))
52
+ - [Google PaLM](https://developers.generativeai.google/products/palm)
53
+ - [Inspur Yuan 1.0](https://air.inspur.com/home)
54
+ - [MiniMax](https://api.minimax.chat/)
55
+ - [XMChat](https://github.com/MILVLG/xmchat)
56
+
57
+ **LLM models via local deployment**:
58
+
59
+ - [ChatGLM](https://github.com/THUDM/ChatGLM-6B) ([ChatGLM2](https://github.com/THUDM/ChatGLM2-6B))
60
+ - [LLaMA](https://github.com/facebookresearch/llama)
61
+ - [StableLM](https://github.com/Stability-AI/StableLM)
62
+ - [MOSS](https://github.com/OpenLMLab/MOSS)
63
+
64
  ## Usage Tips
65
 
66
  - To better control the ChatGPT, use System Prompt.
68
  - 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
+ ## Quickstart
76
 
77
  ```shell
78
  git clone https://github.com/GaiZhenbiao/ChuanhuChatGPT.git
104
  ```
105
  pip install -r requirements.txt
106
  ```
 
 
 
 
107
 
108
  Generally, you can solve most problems by following these steps.
109
 
readme/README_ja.md CHANGED
@@ -6,7 +6,7 @@
6
  <h1 align="center">川虎 Chat 🐯 Chuanhu Chat</h1>
7
  <div align="center">
8
  <a href="https://github.com/GaiZhenBiao/ChuanhuChatGPT">
9
- <img src="https://user-images.githubusercontent.com/70903329/227087087-93b37d64-7dc3-4738-a518-c1cf05591c8a.png" alt="Logo" height="156">
10
  </a>
11
 
12
  <p align="center">
@@ -44,17 +44,34 @@
44
  </p>
45
  </div>
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  ## 使う上でのTips
48
 
49
  - ChatGPTをより適切に制御するために、システムプロンプトを使用できます。
50
  - プロンプトテンプレートを使用するには、プロンプトテンプレートコレクションを選択し、ドロップダウンメニューから特定のプロンプトを選択。回答が不十分な場合は、`🔄再生成`ボタンを使って再試行します。
51
  - 入力ボックスで改行するには、<kbd>Shift</kbd> + <kbd>Enter</kbd>キーを押してください。
52
  - 入力履歴を素早く切り替えるには、入力ボックスで <kbd>↑</kbd>と<kbd>↓</kbd>キーを押す。
53
- - プログラムをサーバにデプロイするには、プログラムの最終行を `demo.launch(server_name="0.0.0.0", server_port=<your port number>)`に変更します。
54
- - 共有リンクを取得するには、プログラムの最後の行を `demo.launch(share=True)` に変更してください。なお、公開リンクでアクセスするためには、プログラムが実行されている必要があることに注意してください。
55
  - Hugging Face Spacesで使用する場合: より速く、より安全に利用するために、**Duplicate Space**を使用し、自分のスペースでプログラムを実行することをお勧めします。
56
 
57
- ## インストール
58
 
59
  ```shell
60
  git clone https://github.com/GaiZhenbiao/ChuanhuChatGPT.git
@@ -86,10 +103,6 @@ python ChuanhuChatbot.py
86
  ```
87
  pip install -r requirements.txt
88
  ```
89
- 3. Gradioを更新
90
- ```
91
- pip install gradio --upgrade --force-reinstall
92
- ```
93
 
94
  一般的に、以下の手順でほとんどの問題を解決することができます。
95
 
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">
44
  </p>
45
  </div>
46
 
47
+ ## サポートされている大規模言語モデル
48
+
49
+ **APIを通じてアクセス可能な大規模言語モデル**:
50
+
51
+ - [ChatGPT](https://chat.openai.com) ([GPT-4](https://openai.com/product/gpt-4))
52
+ - [Google PaLM](https://developers.generativeai.google/products/palm)
53
+ - [Inspur Yuan 1.0](https://air.inspur.com/home)
54
+ - [MiniMax](https://api.minimax.chat/)
55
+ - [XMChat](https://github.com/MILVLG/xmchat)
56
+
57
+ **ローカルに展開された大規模言語モデル**:
58
+
59
+ - [ChatGLM](https://github.com/THUDM/ChatGLM-6B) ([ChatGLM2](https://github.com/THUDM/ChatGLM2-6B))
60
+ - [LLaMA](https://github.com/facebookresearch/llama)
61
+ - [StableLM](https://github.com/Stability-AI/StableLM)
62
+ - [MOSS](https://github.com/OpenLMLab/MOSS)
63
+
64
  ## 使う上でのTips
65
 
66
  - ChatGPTをより適切に制御するために、システムプロンプトを使用できます。
67
  - プロンプトテンプレートを使用するには、プロンプトテンプレートコレクションを選択し、ドロップダウンメニューから特定のプロンプトを選択。回答が不十分な場合は、`🔄再生成`ボタンを使って再試行します。
68
  - 入力ボックスで改行するには、<kbd>Shift</kbd> + <kbd>Enter</kbd>キーを押してください。
69
  - 入力履歴を素早く切り替えるには、入力ボックスで <kbd>↑</kbd>と<kbd>↓</kbd>キーを押す。
70
+ - プログラムをサーバーに展開するには、`config.json` 内の `"server_name": "0.0.0.0", "server_port": <ポート番号>`を設定してください。
71
+ - 共有リンクを取得するには、 `config.json` 内の `"share": true` を設定してください。なお、公開リンクでアクセスするためには、プログラムが実行されている必要があることに注意してください。
72
  - Hugging Face Spacesで使用する場合: より速く、より安全に利用するために、**Duplicate Space**を使用し、自分のスペースでプログラムを実行することをお勧めします。
73
 
74
+ ## クイックスタート
75
 
76
  ```shell
77
  git clone https://github.com/GaiZhenbiao/ChuanhuChatGPT.git
103
  ```
104
  pip install -r requirements.txt
105
  ```
 
 
 
 
106
 
107
  一般的に、以下の手順でほとんどの問題を解決することができます。
108
 
requirements.txt CHANGED
@@ -1,5 +1,5 @@
1
- gradio==3.33.1
2
- gradio_client==0.2.5
3
  pypinyin
4
  tiktoken
5
  socksio
@@ -7,7 +7,7 @@ tqdm
7
  colorama
8
  googlesearch-python
9
  Pygments
10
- langchain==0.0.173
11
  markdown
12
  PyPDF2
13
  pdfplumber
@@ -16,10 +16,13 @@ commentjson
16
  openpyxl
17
  pandoc
18
  wolframalpha
19
- faiss-cpu
20
  duckduckgo-search
21
  arxiv
22
  wikipedia
23
  google.generativeai
24
- openai
25
  unstructured
 
 
 
1
+ gradio==3.40.0
2
+ gradio_client==0.4.0
3
  pypinyin
4
  tiktoken
5
  socksio
7
  colorama
8
  googlesearch-python
9
  Pygments
10
+ langchain==0.0.276
11
  markdown
12
  PyPDF2
13
  pdfplumber
16
  openpyxl
17
  pandoc
18
  wolframalpha
19
+ faiss-cpu==1.7.4
20
  duckduckgo-search
21
  arxiv
22
  wikipedia
23
  google.generativeai
24
+ openai>=0.27.9
25
  unstructured
26
+ google-api-python-client
27
+ tabulate
28
+ ujson
requirements_advanced.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ transformers
2
+ huggingface_hub
3
+ torch
4
+ icetk
5
+ protobuf==3.19.0
6
+ git+https://github.com/OptimalScale/LMFlow.git
7
+ cpm-kernels
8
+ sentence_transformers
9
+ accelerate
10
+ sentencepiece
11
+ datasets