JohnSmith9982/ChuanhuChatGPT

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