MaktubCN commited on
Commit
3ac7a03
·
verified ·
1 Parent(s): 43e3029

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +336 -358
app.py CHANGED
@@ -96,366 +96,344 @@ def main():
96
  # 添加一个隐藏的 Textbox 用于存储 URL 参数
97
  url_params = gr.Textbox(label="URL Parameters", visible=False)
98
 
99
- with gr_L1():
100
- with gr_L2(scale=2, elem_id="gpt-chat"):
101
- chatbot = gr.Chatbot(label=f"当前模型:{LLM_MODEL}", elem_id="gpt-chatbot")
102
- if LAYOUT == "TOP-DOWN":
103
- chatbot.style(height=CHATBOT_HEIGHT)
104
- history = gr.State([])
105
- with gr_L2(scale=1, elem_id="gpt-panel"):
106
- with gr.Accordion("输入区", open=True, elem_id="input-panel") as area_input_primary:
107
- with gr.Row():
108
- txt = gr.Textbox(show_label=False, lines=2, placeholder="输入问题或API密钥,输入多个密钥时,用英文逗号间隔。支持多个OpenAI密钥共存。").style(container=False)
109
- with gr.Row():
110
- submitBtn = gr.Button("提交", elem_id="elem_submit", variant="primary")
111
- with gr.Row():
112
- resetBtn = gr.Button("重置", elem_id="elem_reset", variant="secondary"); resetBtn.style(size="sm")
113
- stopBtn = gr.Button("停止", elem_id="elem_stop", variant="secondary"); stopBtn.style(size="sm")
114
- clearBtn = gr.Button("清除", elem_id="elem_clear", variant="secondary", visible=False); clearBtn.style(size="sm")
115
- # 如果需要启用音频,可以取消下面的注释
116
- # if ENABLE_AUDIO:
117
- # with gr.Row():
118
- # audio_mic = gr.Audio(source="microphone", type="numpy", elem_id="elem_audio", streaming=True, show_label=False).style(container=False)
119
- with gr.Row():
120
- status = gr.Markdown(f"Tip: 按Enter提交, 按Shift+Enter换行。当前模型: {LLM_MODEL} \n {proxy_info}", elem_id="state-panel")
121
-
122
- with gr.Accordion("基础功能区", open=True, elem_id="basic-panel") as area_basic_fn:
123
- with gr.Row():
124
- for k in range(NUM_CUSTOM_BASIC_BTN):
125
- customize_btn = gr.Button("自定义按钮" + str(k+1), visible=False, variant="secondary", info_str=f'基础功能区: 自定义按钮')
126
- customize_btn.style(size="sm")
127
- customize_btns.update({"自定义按钮" + str(k+1): customize_btn})
128
- for k in functional:
129
- if ("Visible" in functional[k]) and (not functional[k]["Visible"]): continue
130
- variant = functional[k]["Color"] if "Color" in functional[k] else "secondary"
131
- functional[k]["Button"] = gr.Button(k, variant=variant, info_str=f'基础功能区: {k}')
132
- functional[k]["Button"].style(size="sm")
133
- predefined_btns.update({k: functional[k]["Button"]})
134
- with gr.Accordion("函数插件区", open=True, elem_id="plugin-panel") as area_crazy_fn:
135
- with gr.Row():
136
- gr.Markdown("插件可读取“输入区”文本/路径作为参数(上传文件自动修正路径)")
137
- with gr.Row(elem_id="input-plugin-group"):
138
- plugin_group_sel = gr.Dropdown(choices=all_plugin_groups, label='', show_label=False, value=DEFAULT_FN_GROUPS,
139
- multiselect=True, interactive=True, elem_classes='normal_mut_select').style(container=False)
140
  with gr.Row():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  for k, plugin in plugins.items():
142
- if not plugin.get("AsButton", True): continue
143
- visible = True if match_group(plugin['Group'], DEFAULT_FN_GROUPS) else False
144
- variant = plugins[k]["Color"] if "Color" in plugin else "secondary"
145
- info = plugins[k].get("Info", k)
146
- plugin['Button'] = plugins[k]['Button'] = gr.Button(k, variant=variant,
147
- visible=visible, info_str=f'函数插件区: {info}').style(size="sm")
148
- with gr.Row():
149
- with gr.Accordion("更多函数插件", open=True):
150
- dropdown_fn_list = []
151
- for k, plugin in plugins.items():
152
- if not match_group(plugin['Group'], DEFAULT_FN_GROUPS): continue
153
- if not plugin.get("AsButton", True): dropdown_fn_list.append(k) # 排除已经是按钮的插件
154
- elif plugin.get('AdvancedArgs', False): dropdown_fn_list.append(k) # 对于需要高级参数的插件,亦在下拉菜单中显示
155
- with gr.Row():
156
- dropdown = gr.Dropdown(dropdown_fn_list, value=r"打开插件列表", label="", show_label=False).style(container=False)
157
- with gr.Row():
158
- plugin_advanced_arg = gr.Textbox(show_label=True, label="高级参数输入区", visible=False,
159
- placeholder="这里是特殊函数插件的高级参数输入区").style(container=False)
160
- with gr.Row():
161
- switchy_bt = gr.Button(r"请先从插件列表中选择", variant="secondary").style(size="sm")
162
- with gr.Row():
163
- with gr.Accordion("点击展开“文件下载区”。", open=False) as area_file_up:
164
- file_upload = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload")
165
-
166
- with gr.Floating(init_x="0%", init_y="0%", visible=True, width=None, drag="forbidden", elem_id="tooltip"):
167
- with gr.Row():
168
- with gr.Tab("上传文件", elem_id="interact-panel"):
169
- gr.Markdown("请上传本地文件/压缩包供“函数插件区”功能调用。请注意: 上传文件后会自动把输入区修改为相应路径。")
170
- file_upload_2 = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload_float")
171
-
172
- with gr.Tab("更换模型", elem_id="interact-panel"):
173
- md_dropdown = gr.Dropdown(AVAIL_LLM_MODELS, value=LLM_MODEL, label="更换LLM模型/请求源").style(container=False)
174
- top_p = gr.Slider(minimum=0, maximum=1.0, value=1.0, step=0.01,interactive=True, label="Top-p (nucleus sampling)",)
175
- temperature = gr.Slider(minimum=0, maximum=2.0, value=1.0, step=0.01, interactive=True, label="Temperature",)
176
- max_length_sl = gr.Slider(minimum=256, maximum=1024*32, value=4096, step=128, interactive=True, label="Local LLM MaxLength",)
177
- system_prompt = gr.Textbox(show_label=True, lines=2, placeholder=f"System Prompt", label="System prompt", value=INIT_SYS_PROMPT)
178
-
179
- with gr.Tab("界面外观", elem_id="interact-panel"):
180
- theme_dropdown = gr.Dropdown(AVAIL_THEMES, value=THEME, label="更换UI主题").style(container=False)
181
- checkboxes = gr.CheckboxGroup(["基础功能区", "函数插件区", "浮动输入区", "输入清除键", "插件参数区"], value=["基础功能区", "函数插件区"], label="显示/隐藏功能区", elem_id='cbs').style(container=False)
182
- opt = ["自定义菜单"]
183
- value=[]
184
- if ADD_WAIFU: opt += ["添加Live2D形象"]; value += ["添加Live2D形象"]
185
- checkboxes_2 = gr.CheckboxGroup(opt, value=value, label="显示/隐藏自定义菜单", elem_id='cbsc').style(container=False)
186
- dark_mode_btn = gr.Button("切换界面明暗 ☀", variant="secondary").style(size="sm")
187
- dark_mode_btn.click(None, None, None, _js=js_code_for_toggle_darkmode)
188
- with gr.Tab("帮助", elem_id="interact-panel"):
189
- gr.Markdown(help_menu_description)
190
-
191
- with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_input_secondary:
192
- with gr.Accordion("浮动输入区", open=True, elem_id="input-panel2"):
193
- with gr.Row() as row:
194
- row.style(equal_height=True)
195
- with gr.Column(scale=10):
196
- txt2 = gr.Textbox(show_label=False, placeholder="Input question here.",
197
- elem_id='user_input_float', lines=8, label="输入区2").style(container=False)
198
- with gr.Column(scale=1, min_width=40):
199
- submitBtn2 = gr.Button("提交", variant="primary"); submitBtn2.style(size="sm")
200
- resetBtn2 = gr.Button("重置", variant="secondary"); resetBtn2.style(size="sm")
201
- stopBtn2 = gr.Button("停止", variant="secondary"); stopBtn2.style(size="sm")
202
- clearBtn2 = gr.Button("清除", elem_id="elem_clear2", variant="secondary", visible=False); clearBtn2.style(size="sm")
203
-
204
- with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_customize:
205
- with gr.Accordion("自定义菜单", open=True, elem_id="edit-panel"):
206
- with gr.Row() as row:
207
- with gr.Column(scale=10):
208
- AVAIL_BTN = [btn for btn in customize_btns.keys()] + [k for k in functional]
209
- basic_btn_dropdown = gr.Dropdown(AVAIL_BTN, value="自定义按钮1", label="选择一个需要自定义基础功能区按钮").style(container=False)
210
- basic_fn_title = gr.Textbox(show_label=False, placeholder="输入新按钮名称", lines=1).style(container=False)
211
- basic_fn_prefix = gr.Textbox(show_label=False, placeholder="输入新提示前缀", lines=4).style(container=False)
212
- basic_fn_suffix = gr.Textbox(show_label=False, placeholder="输入新提示后缀", lines=4).style(container=False)
213
- with gr.Column(scale=1, min_width=70):
214
- basic_fn_confirm = gr.Button("确认并保存", variant="primary"); basic_fn_confirm.style(size="sm")
215
- basic_fn_clean = gr.Button("恢复默认", variant="primary"); basic_fn_clean.style(size="sm")
216
-
217
- def assign_btn(persistent_cookie_, cookies_, basic_btn_dropdown_, basic_fn_title, basic_fn_prefix, basic_fn_suffix, clean_up=False):
218
- ret = {}
219
- # 读取之前的自定义按钮
220
- customize_fn_overwrite_ = cookies_['customize_fn_overwrite']
221
- # 更新新的自定义按钮
222
- customize_fn_overwrite_.update({
223
- basic_btn_dropdown_:
224
- {
225
- "Title":basic_fn_title,
226
- "Prefix":basic_fn_prefix,
227
- "Suffix":basic_fn_suffix,
228
- }
229
  }
230
- )
231
- if clean_up:
232
- customize_fn_overwrite_ = {}
233
- cookies_.update(customize_fn_overwrite_) # 更新cookie
234
- visible = (not clean_up) and (basic_fn_title != "")
235
- if basic_btn_dropdown_ in customize_btns:
236
- # 是自定义按钮,不是预定义按钮
237
- ret.update({customize_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)})
238
- else:
239
- # 是预定义按钮
240
- ret.update({predefined_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)})
241
- ret.update({cookies: cookies_})
242
- try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict
243
- except: persistent_cookie_ = {}
244
- persistent_cookie_["custom_bnt"] = customize_fn_overwrite_ # dict update new value
245
- persistent_cookie_ = to_cookie_str(persistent_cookie_) # persistent cookie to dict
246
- ret.update({py_pickle_cookie: persistent_cookie_}) # write persistent cookie
247
- return ret
248
-
249
- # update btn
250
- h = basic_fn_confirm.click(assign_btn, [py_pickle_cookie, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix],
251
- [py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()])
252
- h.then(None, [py_pickle_cookie], None, _js="""(py_pickle_cookie)=>{setCookie("py_pickle_cookie", py_pickle_cookie, 365);}""")
253
- # clean up btn
254
- h2 = basic_fn_clean.click(assign_btn, [py_pickle_cookie, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix, gr.State(True)],
255
- [py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()])
256
- h2.then(None, [py_pickle_cookie], None, _js="""(py_pickle_cookie)=>{setCookie("py_pickle_cookie", py_pickle_cookie, 365);}""")
257
-
258
- def persistent_cookie_reload(persistent_cookie_, cookies_):
259
- ret = {}
260
- for k in customize_btns:
261
- ret.update({customize_btns[k]: gr.update(visible=False, value="")})
262
-
263
- try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict
264
- except: return ret
265
-
266
- customize_fn_overwrite_ = persistent_cookie_.get("custom_bnt", {})
267
- cookies_['customize_fn_overwrite'] = customize_fn_overwrite_
268
- ret.update({cookies: cookies_})
269
-
270
- for k,v in persistent_cookie_["custom_bnt"].items():
271
- if v['Title'] == "": continue
272
- if k in customize_btns: ret.update({customize_btns[k]: gr.update(visible=True, value=v['Title'])})
273
- else: ret.update({predefined_btns[k]: gr.update(visible=True, value=v['Title'])})
274
- return ret
275
-
276
- # 添加 JavaScript 来解析 URL 参数并设置到隐藏的 Textbox
277
- url_param_js = """
278
- <script>
279
- window.onload = function() {
280
- const params = new URLSearchParams(window.location.search);
281
- let base_url = params.get('base_url') || '';
282
- let api_key = params.get('api_key') || '';
283
- let combined = `base_url=${encodeURIComponent(base_url)}&api_key=${encodeURIComponent(api_key)}`;
284
- // 将解析后的参数设置到隐藏的 Textbox
285
- const urlParamsTextbox = document.querySelector('input[aria-label="URL Parameters"]');
286
- if (urlParamsTextbox) {
287
- urlParamsTextbox.value = combined;
288
- }
289
- }
290
- </script>
291
- """
292
- gr.HTML(url_param_js)
293
-
294
- # 定义从隐藏的 Textbox 中提取 base_url 和 api_key 的函数
295
- def extract_api_credentials(url_params, cookies):
296
- try:
297
- # 解析 URL 参数
298
- parsed = dict(param.split('=') for param in url_params.split('&') if '=' in param)
299
- base_url = parsed.get('base_url', None)
300
- api_key = parsed.get('api_key', None)
301
-
302
- print(f"Extracted base_url: {base_url}")
303
- print(f"Extracted api_key: {api_key}")
304
-
305
- # 更新 cookies 或应用程序状态
306
- if base_url:
307
- cookies['base_url'] = base_url
308
- if api_key:
309
- cookies['api_key'] = api_key # 警告:通过 URL 传递 API 密钥是不安全的
310
-
311
- return cookies
312
- except Exception as e:
313
- print(f"Error in extract_api_credentials: {e}")
314
- return cookies
315
-
316
- # 在应用加载时调用该函数,通过隐藏的 Textbox 获取 URL 参数
317
- demo.load(
318
- fn=extract_api_credentials,
319
- inputs=[url_params, cookies],
320
- outputs=[cookies]
321
- )
322
-
323
- # 准备传递给 predict 函数的输入
324
- input_combo = [cookies, max_length_sl, md_dropdown, txt, txt2, top_p, temperature, chatbot, history, system_prompt, plugin_advanced_arg]
325
- output_combo = [cookies, chatbot, history, status]
326
- predict_args = dict(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True)], outputs=output_combo)
327
-
328
- # 提交按钮和重置按钮
329
- cancel_handles.append(txt.submit(**predict_args))
330
- cancel_handles.append(txt2.submit(**predict_args))
331
- cancel_handles.append(submitBtn.click(**predict_args))
332
- cancel_handles.append(submitBtn2.click(**predict_args))
333
- resetBtn.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status
334
- resetBtn2.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status
335
- resetBtn.click(lambda: ([], [], "已重置"), None, [chatbot, history, status]) # 再在后端清除history
336
- resetBtn2.click(lambda: ([], [], "已重置"), None, [chatbot, history, status]) # 再在后端清除history
337
- clearBtn.click(None, None, [txt, txt2], _js=js_code_clear)
338
- clearBtn2.click(None, None, [txt, txt2], _js=js_code_clear)
339
- if AUTO_CLEAR_TXT:
340
- submitBtn.click(None, None, [txt, txt2], _js=js_code_clear)
341
- submitBtn2.click(None, None, [txt, txt2], _js=js_code_clear)
342
- txt.submit(None, None, [txt, txt2], _js=js_code_clear)
343
- txt2.submit(None, None, [txt, txt2], _js=js_code_clear)
344
- # 基础功能区的回调函数注册
345
- for k in functional:
346
- if ("Visible" in functional[k]) and (not functional[k]["Visible"]): continue
347
- click_handle = functional[k]["Button"].click(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True), gr.State(k)], outputs=output_combo)
348
- cancel_handles.append(click_handle)
349
- for btn in customize_btns.values():
350
- click_handle = btn.click(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True), gr.State(btn.value)], outputs=output_combo)
351
- cancel_handles.append(click_handle)
352
- # 文件上传区,接收文件后与chatbot的互动
353
- file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt, txt2, checkboxes, cookies], [chatbot, txt, txt2, cookies]).then(None, None, None, _js=r"()=>{toast_push('上传完毕 ...'); cancel_loading_status();}")
354
- file_upload_2.upload(on_file_uploaded, [file_upload_2, chatbot, txt, txt2, checkboxes, cookies], [chatbot, txt, txt2, cookies]).then(None, None, None, _js=r"()=>{toast_push('上传完毕 ...'); cancel_loading_status();}")
355
- # 函数插件-固定按钮区
356
- for k in plugins:
357
- if not plugins[k].get("AsButton", True): continue
358
- click_handle = plugins[k]["Button"].click(ArgsGeneralWrapper(plugins[k]["Function"]), [*input_combo], output_combo)
359
- click_handle.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot])
360
- cancel_handles.append(click_handle)
361
- # 函数插件-下拉菜单与随变按钮的互动
362
- def on_dropdown_changed(k):
363
- variant = plugins[k]["Color"] if "Color" in plugins else "secondary"
364
- info = plugins[k].get("Info", k)
365
- ret = {switchy_bt: gr.update(value=k, variant=variant, info_str=f'函数插件区: {info}')}
366
- if plugins[k].get("AdvancedArgs", False): # 是否唤起高级插件参数区
367
- ret.update({plugin_advanced_arg: gr.update(visible=True, label=f"插件[{k}]的高级参数说明:" + plugins[k].get("ArgsReminder", [f"没有提供高级参数功能说明"]))})
368
- else:
369
- ret.update({plugin_advanced_arg: gr.update(visible=False, label=f"插件[{k}]不需要高级参数。")})
370
- return ret
371
- dropdown.select(on_dropdown_changed, [dropdown], [switchy_bt, plugin_advanced_arg] )
372
-
373
- def on_md_dropdown_changed(k):
374
- return {chatbot: gr.update(label="当前模型:"+k)}
375
- md_dropdown.select(on_md_dropdown_changed, [md_dropdown], [chatbot] )
376
-
377
- def on_theme_dropdown_changed(theme, secret_css):
378
- adjust_theme_func, css_part1, _, adjust_dynamic_theme = load_dynamic_theme(theme)
379
- if adjust_dynamic_theme:
380
- css_part2 = adjust_dynamic_theme._get_theme_css()
381
- else:
382
- css_part2 = adjust_theme_func()._get_theme_css()
383
- return css_part2 + css_part1
384
-
385
- theme_handle = theme_dropdown.select(on_theme_dropdown_changed, [theme_dropdown, secret_css], [secret_css])
386
- theme_handle.then(
387
- None,
388
- [secret_css],
389
- None,
390
- _js=js_code_for_css_changing
391
- )
392
- # 随变按钮的回调函数注册
393
- def route(k, *args, **kwargs):
394
- if k in [r"打开插件列表", r"请先从插件列表中选择"]: return
395
- return ArgsGeneralWrapper(plugins[k]["Function"])(*args, **kwargs)
396
- click_handle = switchy_bt.click(route,[switchy_bt, *input_combo], output_combo)
397
  click_handle.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot])
398
  cancel_handles.append(click_handle)
399
- # 终止按钮的回调函数注册
400
- stopBtn.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
401
- stopBtn2.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
402
- plugins_as_btn = {name:plugin for name, plugin in plugins.items() if plugin.get('Button', None)}
403
- def on_group_change(group_list):
404
- btn_list = []
405
- fns_list = []
406
- if not group_list: # 处理特殊情况:没有选择任何插件组
407
- return [*[plugin['Button'].update(visible=False) for _, plugin in plugins_as_btn.items()], gr.Dropdown.update(choices=[])]
408
- for k, plugin in plugins.items():
409
- if plugin.get("AsButton", True):
410
- btn_list.append(plugin['Button'].update(visible=match_group(plugin['Group'], group_list))) # 刷新按钮
411
- if plugin.get('AdvancedArgs', False): fns_list.append(k) # 对于需要高级参数的插件,亦在下拉菜单中显示
412
- elif match_group(plugin['Group'], group_list): fns_list.append(k) # 刷新下拉列表
413
- return [*btn_list, gr.Dropdown.update(choices=fns_list)]
414
- plugin_group_sel.select(fn=on_group_change, inputs=[plugin_group_sel], outputs=[*[plugin['Button'] for name, plugin in plugins_as_btn.items()], dropdown])
415
- if ENABLE_AUDIO:
416
- from crazy_functions.live_audio.audio_io import RealtimeAudioDistribution
417
- rad = RealtimeAudioDistribution()
418
- def deal_audio(audio, cookies):
419
- rad.feed(cookies['uuid'].hex, audio)
420
- audio_mic.stream(deal_audio, inputs=[audio_mic, cookies])
421
-
422
- # 定义从隐藏的 Textbox 中提取 base_url 和 api_key 的函数(已定义上面)
423
- # 已在上面调用
424
-
425
- # 启动 Gradio 的延迟任务
426
- def run_delayed_tasks():
427
- import threading, webbrowser, time
428
- print(f"如果浏览器没有自动打开,请复制并转到以下URL:")
429
- if DARK_MODE:
430
- print(f"\t「暗色主题已启用(支持动态切换主题)」: http://localhost:{PORT}")
431
- else:
432
- print(f"\t「亮色主题已启用(支持动态切换主题)」: http://localhost:{PORT}")
433
-
434
- def auto_updates():
435
- time.sleep(0)
436
- auto_update()
437
- def open_browser():
438
- time.sleep(2)
439
- webbrowser.open_new_tab(f"http://localhost:{PORT}")
440
- def warm_up_mods():
441
- time.sleep(6)
442
- warm_up_modules()
443
-
444
- threading.Thread(target=auto_updates, name="self-upgrade", daemon=True).start() # 查看自动更新
445
- threading.Thread(target=open_browser, name="open-browser", daemon=True).start() # 打开浏览器页面
446
- threading.Thread(target=warm_up_mods, name="warm-up", daemon=True).start() # 预热tiktoken模块
447
-
448
- run_delayed_tasks()
449
- demo.queue(concurrency_count=CONCURRENT_COUNT).launch(server_name="0.0.0.0", share=False, favicon_path="docs/logo.png", blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile"])
450
-
451
- # 如果需要在二级路径下运行
452
- # CUSTOM_PATH = get_conf('CUSTOM_PATH')
453
- # if CUSTOM_PATH != "/":
454
- # from toolbox import run_gradio_in_subpath
455
- # run_gradio_in_subpath(demo, auth=AUTHENTICATION, port=PORT, custom_path=CUSTOM_PATH)
456
- # else:
457
- # demo.launch(server_name="0.0.0.0", server_port=PORT, auth=AUTHENTICATION, favicon_path="docs/logo.png",
458
- # blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile",f"{PATH_LOGGING}/admin"])
459
-
460
- if __name__ == "__main__":
461
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  # 添加一个隐藏的 Textbox 用于存储 URL 参数
97
  url_params = gr.Textbox(label="URL Parameters", visible=False)
98
 
99
+ with gr_L1():
100
+ with gr_L2(scale=2, elem_id="gpt-chat"):
101
+ chatbot = gr.Chatbot(label=f"当前模型:{LLM_MODEL}", elem_id="gpt-chatbot")
102
+ if LAYOUT == "TOP-DOWN": chatbot.style(height=CHATBOT_HEIGHT)
103
+ history = gr.State([])
104
+ with gr_L2(scale=1, elem_id="gpt-panel"):
105
+ with gr.Accordion("输入区", open=True, elem_id="input-panel") as area_input_primary:
106
+ with gr.Row():
107
+ txt = gr.Textbox(show_label=False, lines=2, placeholder="输入问题或API密钥,输入多个密钥时,用英文逗号间隔。支持多个OpenAI密钥共存。").style(container=False)
108
+ with gr.Row():
109
+ submitBtn = gr.Button("提交", elem_id="elem_submit", variant="primary")
110
+ with gr.Row():
111
+ resetBtn = gr.Button("重置", elem_id="elem_reset", variant="secondary"); resetBtn.style(size="sm")
112
+ stopBtn = gr.Button("停止", elem_id="elem_stop", variant="secondary"); stopBtn.style(size="sm")
113
+ clearBtn = gr.Button("清除", elem_id="elem_clear", variant="secondary", visible=False); clearBtn.style(size="sm")
114
+ if ENABLE_AUDIO:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  with gr.Row():
116
+ audio_mic = gr.Audio(source="microphone", type="numpy", elem_id="elem_audio", streaming=True, show_label=False).style(container=False)
117
+ with gr.Row():
118
+ status = gr.Markdown(f"Tip: 按Enter提交, 按Shift+Enter换行。当前模型: {LLM_MODEL} \n {proxy_info}", elem_id="state-panel")
119
+
120
+ with gr.Accordion("基础功能区", open=True, elem_id="basic-panel") as area_basic_fn:
121
+ with gr.Row():
122
+ for k in range(NUM_CUSTOM_BASIC_BTN):
123
+ customize_btn = gr.Button("自定义按钮" + str(k+1), visible=False, variant="secondary", info_str=f'基础功能区: 自定义按钮')
124
+ customize_btn.style(size="sm")
125
+ customize_btns.update({"自定义按钮" + str(k+1): customize_btn})
126
+ for k in functional:
127
+ if ("Visible" in functional[k]) and (not functional[k]["Visible"]): continue
128
+ variant = functional[k]["Color"] if "Color" in functional[k] else "secondary"
129
+ functional[k]["Button"] = gr.Button(k, variant=variant, info_str=f'基础功能区: {k}')
130
+ functional[k]["Button"].style(size="sm")
131
+ predefined_btns.update({k: functional[k]["Button"]})
132
+ with gr.Accordion("函数插件区", open=True, elem_id="plugin-panel") as area_crazy_fn:
133
+ with gr.Row():
134
+ gr.Markdown("插件可读取“输入区”文本/路径作为参数(上传文件自动修正路径)")
135
+ with gr.Row(elem_id="input-plugin-group"):
136
+ plugin_group_sel = gr.Dropdown(choices=all_plugin_groups, label='', show_label=False, value=DEFAULT_FN_GROUPS,
137
+ multiselect=True, interactive=True, elem_classes='normal_mut_select').style(container=False)
138
+ with gr.Row():
139
+ for k, plugin in plugins.items():
140
+ if not plugin.get("AsButton", True): continue
141
+ visible = True if match_group(plugin['Group'], DEFAULT_FN_GROUPS) else False
142
+ variant = plugins[k]["Color"] if "Color" in plugin else "secondary"
143
+ info = plugins[k].get("Info", k)
144
+ plugin['Button'] = plugins[k]['Button'] = gr.Button(k, variant=variant,
145
+ visible=visible, info_str=f'函数插件区: {info}').style(size="sm")
146
+ with gr.Row():
147
+ with gr.Accordion("更多函数插件", open=True):
148
+ dropdown_fn_list = []
149
  for k, plugin in plugins.items():
150
+ if not match_group(plugin['Group'], DEFAULT_FN_GROUPS): continue
151
+ if not plugin.get("AsButton", True): dropdown_fn_list.append(k) # 排除已经是按钮的插件
152
+ elif plugin.get('AdvancedArgs', False): dropdown_fn_list.append(k) # 对于需要高级参数的插件,亦在下拉菜单中显示
153
+ with gr.Row():
154
+ dropdown = gr.Dropdown(dropdown_fn_list, value=r"打开插件列表", label="", show_label=False).style(container=False)
155
+ with gr.Row():
156
+ plugin_advanced_arg = gr.Textbox(show_label=True, label="高级参数输入区", visible=False,
157
+ placeholder="这里是特殊函数插件的高级参数输入区").style(container=False)
158
+ with gr.Row():
159
+ switchy_bt = gr.Button(r"请先从插件列表中选择", variant="secondary").style(size="sm")
160
+ with gr.Row():
161
+ with gr.Accordion("点击展开“文件下载区”。", open=False) as area_file_up:
162
+ file_upload = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload")
163
+
164
+ with gr.Floating(init_x="0%", init_y="0%", visible=True, width=None, drag="forbidden", elem_id="tooltip"):
165
+ with gr.Row():
166
+ with gr.Tab("上传文件", elem_id="interact-panel"):
167
+ gr.Markdown("请上传本地文件/压缩包供“函数插件区”功能调用。请注意: 上传文件后会自动把输入区修改为相应路径。")
168
+ file_upload_2 = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload_float")
169
+
170
+ with gr.Tab("更换模型", elem_id="interact-panel"):
171
+ md_dropdown = gr.Dropdown(AVAIL_LLM_MODELS, value=LLM_MODEL, label="更换LLM模型/请求源").style(container=False)
172
+ top_p = gr.Slider(minimum=-0, maximum=1.0, value=1.0, step=0.01,interactive=True, label="Top-p (nucleus sampling)",)
173
+ temperature = gr.Slider(minimum=-0, maximum=2.0, value=1.0, step=0.01, interactive=True, label="Temperature",)
174
+ max_length_sl = gr.Slider(minimum=256, maximum=1024*32, value=4096, step=128, interactive=True, label="Local LLM MaxLength",)
175
+ system_prompt = gr.Textbox(show_label=True, lines=2, placeholder=f"System Prompt", label="System prompt", value=INIT_SYS_PROMPT)
176
+
177
+ with gr.Tab("界面外观", elem_id="interact-panel"):
178
+ theme_dropdown = gr.Dropdown(AVAIL_THEMES, value=THEME, label="更换UI主题").style(container=False)
179
+ checkboxes = gr.CheckboxGroup(["基础功能区", "函数插件区", "浮动输入区", "输入清除键", "插件参数区"], value=["基础功能区", "函数插件区"], label="显示/隐藏功能区", elem_id='cbs').style(container=False)
180
+ opt = ["自定义菜单"]
181
+ value=[]
182
+ if ADD_WAIFU: opt += ["添加Live2D形象"]; value += ["添加Live2D形象"]
183
+ checkboxes_2 = gr.CheckboxGroup(opt, value=value, label="显示/隐藏自定义菜单", elem_id='cbsc').style(container=False)
184
+ dark_mode_btn = gr.Button("切换界面明暗 ☀", variant="secondary").style(size="sm")
185
+ dark_mode_btn.click(None, None, None, _js=js_code_for_toggle_darkmode)
186
+ with gr.Tab("帮助", elem_id="interact-panel"):
187
+ gr.Markdown(help_menu_description)
188
+
189
+ with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_input_secondary:
190
+ with gr.Accordion("浮动输入区", open=True, elem_id="input-panel2"):
191
+ with gr.Row() as row:
192
+ row.style(equal_height=True)
193
+ with gr.Column(scale=10):
194
+ txt2 = gr.Textbox(show_label=False, placeholder="Input question here.",
195
+ elem_id='user_input_float', lines=8, label="输入区2").style(container=False)
196
+ with gr.Column(scale=1, min_width=40):
197
+ submitBtn2 = gr.Button("提交", variant="primary"); submitBtn2.style(size="sm")
198
+ resetBtn2 = gr.Button("重置", variant="secondary"); resetBtn2.style(size="sm")
199
+ stopBtn2 = gr.Button("停止", variant="secondary"); stopBtn2.style(size="sm")
200
+ clearBtn2 = gr.Button("清除", elem_id="elem_clear2", variant="secondary", visible=False); clearBtn2.style(size="sm")
201
+
202
+
203
+ with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_customize:
204
+ with gr.Accordion("自定义菜单", open=True, elem_id="edit-panel"):
205
+ with gr.Row() as row:
206
+ with gr.Column(scale=10):
207
+ AVAIL_BTN = [btn for btn in customize_btns.keys()] + [k for k in functional]
208
+ basic_btn_dropdown = gr.Dropdown(AVAIL_BTN, value="自定义按钮1", label="选择一个需要自定义基础功能区按钮").style(container=False)
209
+ basic_fn_title = gr.Textbox(show_label=False, placeholder="输入新按钮名称", lines=1).style(container=False)
210
+ basic_fn_prefix = gr.Textbox(show_label=False, placeholder="输入新提示前缀", lines=4).style(container=False)
211
+ basic_fn_suffix = gr.Textbox(show_label=False, placeholder="输入新提示后缀", lines=4).style(container=False)
212
+ with gr.Column(scale=1, min_width=70):
213
+ basic_fn_confirm = gr.Button("确认并保存", variant="primary"); basic_fn_confirm.style(size="sm")
214
+ basic_fn_clean = gr.Button("恢复默认", variant="primary"); basic_fn_clean.style(size="sm")
215
+ def assign_btn(persistent_cookie_, cookies_, basic_btn_dropdown_, basic_fn_title, basic_fn_prefix, basic_fn_suffix, clean_up=False):
216
+ ret = {}
217
+ # 读取之前的自定义按钮
218
+ customize_fn_overwrite_ = cookies_['customize_fn_overwrite']
219
+ # 更新新的自定义按钮
220
+ customize_fn_overwrite_.update({
221
+ basic_btn_dropdown_:
222
+ {
223
+ "Title":basic_fn_title,
224
+ "Prefix":basic_fn_prefix,
225
+ "Suffix":basic_fn_suffix,
 
 
 
 
 
 
 
 
 
 
 
226
  }
227
+ }
228
+ )
229
+ if clean_up:
230
+ customize_fn_overwrite_ = {}
231
+ cookies_.update(customize_fn_overwrite_) # 更新cookie
232
+ visible = (not clean_up) and (basic_fn_title != "")
233
+ if basic_btn_dropdown_ in customize_btns:
234
+ # 是自定义按钮,不是预定义按钮
235
+ ret.update({customize_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)})
236
+ else:
237
+ # 是预定义按钮
238
+ ret.update({predefined_btns[basic_btn_dropdown_]: gr.update(visible=visible, value=basic_fn_title)})
239
+ ret.update({cookies: cookies_})
240
+ try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict
241
+ except: persistent_cookie_ = {}
242
+ persistent_cookie_["custom_bnt"] = customize_fn_overwrite_ # dict update new value
243
+ persistent_cookie_ = to_cookie_str(persistent_cookie_) # persistent cookie to dict
244
+ ret.update({py_pickle_cookie: persistent_cookie_}) # write persistent cookie
245
+ return ret
246
+
247
+ # update btn
248
+ h = basic_fn_confirm.click(assign_btn, [py_pickle_cookie, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix],
249
+ [py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()])
250
+ h.then(None, [py_pickle_cookie], None, _js="""(py_pickle_cookie)=>{setCookie("py_pickle_cookie", py_pickle_cookie, 365);}""")
251
+ # clean up btn
252
+ h2 = basic_fn_clean.click(assign_btn, [py_pickle_cookie, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix, gr.State(True)],
253
+ [py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()])
254
+ h2.then(None, [py_pickle_cookie], None, _js="""(py_pickle_cookie)=>{setCookie("py_pickle_cookie", py_pickle_cookie, 365);}""")
255
+
256
+ def persistent_cookie_reload(persistent_cookie_, cookies_):
257
+ ret = {}
258
+ for k in customize_btns:
259
+ ret.update({customize_btns[k]: gr.update(visible=False, value="")})
260
+
261
+ try: persistent_cookie_ = from_cookie_str(persistent_cookie_) # persistent cookie to dict
262
+ except: return ret
263
+
264
+ customize_fn_overwrite_ = persistent_cookie_.get("custom_bnt", {})
265
+ cookies_['customize_fn_overwrite'] = customize_fn_overwrite_
266
+ ret.update({cookies: cookies_})
267
+
268
+ for k,v in persistent_cookie_["custom_bnt"].items():
269
+ if v['Title'] == "": continue
270
+ if k in customize_btns: ret.update({customize_btns[k]: gr.update(visible=True, value=v['Title'])})
271
+ else: ret.update({predefined_btns[k]: gr.update(visible=True, value=v['Title'])})
272
+ return ret
273
+
274
+ # 功能区显示开关与功能区的互动
275
+ def fn_area_visibility(a):
276
+ ret = {}
277
+ ret.update({area_input_primary: gr.update(visible=("浮动输入区" not in a))})
278
+ ret.update({area_input_secondary: gr.update(visible=("浮动输入区" in a))})
279
+ ret.update({plugin_advanced_arg: gr.update(visible=("插件参数区" in a))})
280
+ if "浮动输入区" in a: ret.update({txt: gr.update(value="")})
281
+ return ret
282
+ checkboxes.select(fn_area_visibility, [checkboxes], [area_basic_fn, area_crazy_fn, area_input_primary, area_input_secondary, txt, txt2, plugin_advanced_arg] )
283
+ checkboxes.select(None, [checkboxes], None, _js=js_code_show_or_hide)
284
+
285
+ # 功能区显示开关与功能区的互动
286
+ def fn_area_visibility_2(a):
287
+ ret = {}
288
+ ret.update({area_customize: gr.update(visible=("自定义菜单" in a))})
289
+ return ret
290
+ checkboxes_2.select(fn_area_visibility_2, [checkboxes_2], [area_customize] )
291
+ checkboxes_2.select(None, [checkboxes_2], None, _js=js_code_show_or_hide_group2)
292
+
293
+ # 整理反复出现的控件句柄组合
294
+ input_combo = [cookies, max_length_sl, md_dropdown, txt, txt2, top_p, temperature, chatbot, history, system_prompt, plugin_advanced_arg]
295
+ output_combo = [cookies, chatbot, history, status]
296
+ predict_args = dict(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True)], outputs=output_combo)
297
+ # 提交按钮、重置按钮
298
+ cancel_handles.append(txt.submit(**predict_args))
299
+ cancel_handles.append(txt2.submit(**predict_args))
300
+ cancel_handles.append(submitBtn.click(**predict_args))
301
+ cancel_handles.append(submitBtn2.click(**predict_args))
302
+ resetBtn.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status
303
+ resetBtn2.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status
304
+ resetBtn.click(lambda: ([], [], "已重置"), None, [chatbot, history, status]) # 再在后端清除history
305
+ resetBtn2.click(lambda: ([], [], "已重置"), None, [chatbot, history, status]) # 再在后端清除history
306
+ clearBtn.click(None, None, [txt, txt2], _js=js_code_clear)
307
+ clearBtn2.click(None, None, [txt, txt2], _js=js_code_clear)
308
+ if AUTO_CLEAR_TXT:
309
+ submitBtn.click(None, None, [txt, txt2], _js=js_code_clear)
310
+ submitBtn2.click(None, None, [txt, txt2], _js=js_code_clear)
311
+ txt.submit(None, None, [txt, txt2], _js=js_code_clear)
312
+ txt2.submit(None, None, [txt, txt2], _js=js_code_clear)
313
+ # 基础功能区的回调函数注册
314
+ for k in functional:
315
+ if ("Visible" in functional[k]) and (not functional[k]["Visible"]): continue
316
+ click_handle = functional[k]["Button"].click(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True), gr.State(k)], outputs=output_combo)
317
+ cancel_handles.append(click_handle)
318
+ for btn in customize_btns.values():
319
+ click_handle = btn.click(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True), gr.State(btn.value)], outputs=output_combo)
320
+ cancel_handles.append(click_handle)
321
+ # 文件上传区,接收文件后与chatbot的互动
322
+ file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt, txt2, checkboxes, cookies], [chatbot, txt, txt2, cookies]).then(None, None, None, _js=r"()=>{toast_push('上传完毕 ...'); cancel_loading_status();}")
323
+ file_upload_2.upload(on_file_uploaded, [file_upload_2, chatbot, txt, txt2, checkboxes, cookies], [chatbot, txt, txt2, cookies]).then(None, None, None, _js=r"()=>{toast_push('上传完毕 ...'); cancel_loading_status();}")
324
+ # 函数插件-固定按钮区
325
+ for k in plugins:
326
+ if not plugins[k].get("AsButton", True): continue
327
+ click_handle = plugins[k]["Button"].click(ArgsGeneralWrapper(plugins[k]["Function"]), [*input_combo], output_combo)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
  click_handle.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot])
329
  cancel_handles.append(click_handle)
330
+ # 函数插件-下拉菜单与随变按钮的互动
331
+ def on_dropdown_changed(k):
332
+ variant = plugins[k]["Color"] if "Color" in plugins[k] else "secondary"
333
+ info = plugins[k].get("Info", k)
334
+ ret = {switchy_bt: gr.update(value=k, variant=variant, info_str=f'函数插件区: {info}')}
335
+ if plugins[k].get("AdvancedArgs", False): # 是否唤起高级插件参数区
336
+ ret.update({plugin_advanced_arg: gr.update(visible=True, label=f"插件[{k}]的高级参数说明:" + plugins[k].get("ArgsReminder", [f"没有提供高级参数功能说明"]))})
337
+ else:
338
+ ret.update({plugin_advanced_arg: gr.update(visible=False, label=f"插件[{k}]不需要高级参数。")})
339
+ return ret
340
+ dropdown.select(on_dropdown_changed, [dropdown], [switchy_bt, plugin_advanced_arg] )
341
+
342
+ def on_md_dropdown_changed(k):
343
+ return {chatbot: gr.update(label="当前模型:"+k)}
344
+ md_dropdown.select(on_md_dropdown_changed, [md_dropdown], [chatbot] )
345
+
346
+ def on_theme_dropdown_changed(theme, secret_css):
347
+ adjust_theme, css_part1, _, adjust_dynamic_theme = load_dynamic_theme(theme)
348
+ if adjust_dynamic_theme:
349
+ css_part2 = adjust_dynamic_theme._get_theme_css()
350
+ else:
351
+ css_part2 = adjust_theme()._get_theme_css()
352
+ return css_part2 + css_part1
353
+
354
+ theme_handle = theme_dropdown.select(on_theme_dropdown_changed, [theme_dropdown, secret_css], [secret_css])
355
+ theme_handle.then(
356
+ None,
357
+ [secret_css],
358
+ None,
359
+ _js=js_code_for_css_changing
360
+ )
361
+ # 随变按钮的回调函数注册
362
+ def route(request: gr.Request, k, *args, **kwargs):
363
+ if k in [r"打开插件列表", r"请先从插件列表中选择"]: return
364
+ yield from ArgsGeneralWrapper(plugins[k]["Function"])(request, *args, **kwargs)
365
+ click_handle = switchy_bt.click(route,[switchy_bt, *input_combo], output_combo)
366
+ click_handle.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot])
367
+ cancel_handles.append(click_handle)
368
+ # 终止按钮的回调函数注册
369
+ stopBtn.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
370
+ stopBtn2.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
371
+ plugins_as_btn = {name:plugin for name, plugin in plugins.items() if plugin.get('Button', None)}
372
+ def on_group_change(group_list):
373
+ btn_list = []
374
+ fns_list = []
375
+ if not group_list: # 处理特殊情况:没有选择任何插件组
376
+ return [*[plugin['Button'].update(visible=False) for _, plugin in plugins_as_btn.items()], gr.Dropdown.update(choices=[])]
377
+ for k, plugin in plugins.items():
378
+ if plugin.get("AsButton", True):
379
+ btn_list.append(plugin['Button'].update(visible=match_group(plugin['Group'], group_list))) # 刷新按钮
380
+ if plugin.get('AdvancedArgs', False): dropdown_fn_list.append(k) # 对于需要高级参数的插件,亦在下拉菜单中显示
381
+ elif match_group(plugin['Group'], group_list): fns_list.append(k) # 刷新下拉列表
382
+ return [*btn_list, gr.Dropdown.update(choices=fns_list)]
383
+ plugin_group_sel.select(fn=on_group_change, inputs=[plugin_group_sel], outputs=[*[plugin['Button'] for name, plugin in plugins_as_btn.items()], dropdown])
384
+ if ENABLE_AUDIO:
385
+ from crazy_functions.live_audio.audio_io import RealtimeAudioDistribution
386
+ rad = RealtimeAudioDistribution()
387
+ def deal_audio(audio, cookies):
388
+ rad.feed(cookies['uuid'].hex, audio)
389
+ audio_mic.stream(deal_audio, inputs=[audio_mic, cookies])
390
+
391
+
392
+ demo.load(init_cookie, inputs=[cookies], outputs=[cookies])
393
+ demo.load(persistent_cookie_reload, inputs = [py_pickle_cookie, cookies],
394
+ outputs = [py_pickle_cookie, cookies, *customize_btns.values(), *predefined_btns.values()], _js=js_code_for_persistent_cookie_init)
395
+ demo.load(None, inputs=[dark_mode], outputs=None, _js="""(dark_mode)=>{apply_cookie_for_checkbox(dark_mode);}""") # 配置暗色主题或亮色主题
396
+ demo.load(None, inputs=[gr.Textbox(LAYOUT, visible=False)], outputs=None, _js='(LAYOUT)=>{GptAcademicJavaScriptInit(LAYOUT);}')
397
+
398
+ # 启动 Gradio 的延迟任务
399
+ def run_delayed_tasks():
400
+ import threading, webbrowser, time
401
+ print(f"如果浏览器没有自动打开,请复制并转到以下URL:")
402
+ if DARK_MODE:
403
+ print(f"\t「暗色主题已启用(支持动态切换主题)」: http://localhost:{PORT}")
404
+ else:
405
+ print(f"\t「亮色主题已启用(支持动态切换主题)」: http://localhost:{PORT}")
406
+
407
+ def auto_updates():
408
+ time.sleep(0)
409
+ auto_update()
410
+ def open_browser():
411
+ time.sleep(2)
412
+ webbrowser.open_new_tab(f"http://localhost:{PORT}")
413
+ def warm_up_mods():
414
+ time.sleep(6)
415
+ warm_up_modules()
416
+
417
+ threading.Thread(target=auto_updates, name="self-upgrade", daemon=True).start() # 查看自动更新
418
+ threading.Thread(target=open_browser, name="open-browser", daemon=True).start() # 打开浏览器页面
419
+ threading.Thread(target=warm_up_mods, name="warm-up", daemon=True).start() # 预热tiktoken模块
420
+
421
+ run_delayed_tasks()
422
+ demo.queue(concurrency_count=CONCURRENT_COUNT).launch(server_name="0.0.0.0", share=False, favicon_path="docs/logo.png", blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile"])
423
+
424
+ # 如果需要在二级路径下运行
425
+ # CUSTOM_PATH = get_conf('CUSTOM_PATH')
426
+ # if CUSTOM_PATH != "/":
427
+ # from toolbox import run_gradio_in_subpath
428
+ # run_gradio_in_subpath(demo, auth=AUTHENTICATION, port=PORT, custom_path=CUSTOM_PATH)
429
+ # else:
430
+ # demo.launch(server_name="0.0.0.0", server_port=PORT, auth=AUTHENTICATION, favicon_path="docs/logo.png",
431
+ # blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile",f"{PATH_LOGGING}/admin"])
432
+
433
+ except Exception as e:
434
+ print("Unhandled exception during application startup:")
435
+ traceback.print_exc()
436
+ sys.exit(1)
437
+
438
+ if __name__ == "__main__":
439
+ main()