每个插件可以归属多个Group

This commit is contained in:
qingxu fu 2023-08-31 15:59:19 +08:00
parent 2d5a1fbc12
commit b31abbcad3
2 changed files with 64 additions and 76 deletions

View File

@ -168,7 +168,7 @@ def get_crazy_functions():
"Function": HotReload(对话历史存档) "Function": HotReload(对话历史存档)
}, },
"[多线程Demo]解析此项目本身(源码自译解)": { "[多线程Demo]解析此项目本身(源码自译解)": {
"Group": "对话", "Group": "对话|编程",
"AsButton": False, # 加入下拉菜单中 "AsButton": False, # 加入下拉菜单中
"Function": HotReload(解析项目本身) "Function": HotReload(解析项目本身)
}, },
@ -499,13 +499,23 @@ def get_crazy_functions():
# except: # except:
# print('Load function plugin failed') # print('Load function plugin failed')
regroupped_functions = {}
"""
设置默认值:
- 默认 Group = 对话
- 默认 AsButton = True
- 默认 AdvancedArgs = False
- 默认 Color = secondary
"""
for name, function_meta in function_plugins.items(): for name, function_meta in function_plugins.items():
if "Group" in function_meta: if "Group" not in function_meta:
groups = function_meta["Group"].split('|') function_plugins[name]["Group"] = '对话'
else: if "AsButton" not in function_meta:
groups = ['对话'] function_plugins[name]["AsButton"] = True
for gruop in groups: if "AdvancedArgs" not in function_meta:
regroupped_functions[gruop] = regroupped_functions.get(gruop, {}) function_plugins[name]["AdvancedArgs"] = False
regroupped_functions[gruop].update({name: function_meta}) if "Color" not in function_meta:
return regroupped_functions function_plugins[name]["Color"] = 'secondary'
return function_plugins

110
main.py
View File

@ -5,19 +5,20 @@ def main():
# if gr.__version__ not in ['3.28.3','3.32.2']: assert False, "需要特殊依赖,请务必用 pip install -r requirements.txt 指令安装依赖详情信息见requirements.txt" # if gr.__version__ not in ['3.28.3','3.32.2']: assert False, "需要特殊依赖,请务必用 pip install -r requirements.txt 指令安装依赖详情信息见requirements.txt"
from request_llm.bridge_all import predict from request_llm.bridge_all import predict
from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, load_chat_cookies, DummyWith from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, load_chat_cookies, DummyWith
# 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到 # 建议您复制一个config_private.py放自己的秘密, 如API和代理网址, 避免不小心传github被别人看到
proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION, CHATBOT_HEIGHT, LAYOUT, AVAIL_LLM_MODELS, AUTO_CLEAR_TXT = \ proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION = get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION')
get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION', 'CHATBOT_HEIGHT', 'LAYOUT', 'AVAIL_LLM_MODELS', 'AUTO_CLEAR_TXT') CHATBOT_HEIGHT, LAYOUT, AVAIL_LLM_MODELS, AUTO_CLEAR_TXT = get_conf('CHATBOT_HEIGHT', 'LAYOUT', 'AVAIL_LLM_MODELS', 'AUTO_CLEAR_TXT')
ENABLE_AUDIO, AUTO_CLEAR_TXT = get_conf('ENABLE_AUDIO', 'AUTO_CLEAR_TXT') ENABLE_AUDIO, AUTO_CLEAR_TXT = get_conf('ENABLE_AUDIO', 'AUTO_CLEAR_TXT')
# 如果WEB_PORT是-1, 则随机选取WEB端口 # 如果WEB_PORT是-1, 则随机选取WEB端口
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
if not AUTHENTICATION: AUTHENTICATION = None
from check_proxy import get_current_version from check_proxy import get_current_version
from themes.theme import adjust_theme, advanced_css, theme_declaration from themes.theme import adjust_theme, advanced_css, theme_declaration
initial_prompt = "Serve me as a writing and programming assistant." initial_prompt = "Serve me as a writing and programming assistant."
title_html = f"<h1 align=\"center\">GPT 学术优化 {get_current_version()}</h1>{theme_declaration}" title_html = f"<h1 align=\"center\">GPT 学术优化 {get_current_version()}</h1>{theme_declaration}"
description = """代码开源和更新[地址🚀](https://github.com/binary-husky/chatgpt_academic),感谢热情的[开发者们❤️](https://github.com/binary-husky/chatgpt_academic/graphs/contributors)""" description = "代码开源和更新[地址🚀](https://github.com/binary-husky/gpt_academic)"
description += "感谢热情的[开发者们❤️](https://github.com/binary-husky/gpt_academic/graphs/contributors)"
# 问询记录, python 版本建议3.9+(越新越好) # 问询记录, python 版本建议3.9+(越新越好)
import logging, uuid import logging, uuid
@ -35,12 +36,9 @@ def main():
# 高级函数插件 # 高级函数插件
from crazy_functional import get_crazy_functions from crazy_functional import get_crazy_functions
DEFAULT_FN_GROUPS, = get_conf('DEFAULT_FN_GROUPS') DEFAULT_FN_GROUPS, = get_conf('DEFAULT_FN_GROUPS')
crazy_fns_role = get_crazy_functions() plugins = get_crazy_functions()
crazy_classification = [i for i in crazy_fns_role] all_plugin_groups = list(set([g for _, plugin in plugins.items() for g in plugin['Group'].split('|')]))
crazy_fns = {} match_group = lambda tags, groups: any([g in groups for g in tags.split('|')])
for role in crazy_fns_role:
for k in crazy_fns_role[role]:
crazy_fns[k] = crazy_fns_role[role][k]
# 处理markdown文本格式的转变 # 处理markdown文本格式的转变
gr.Chatbot.postprocess = format_io gr.Chatbot.postprocess = format_io
@ -94,35 +92,21 @@ def main():
with gr.Row(): with gr.Row():
gr.Markdown("插件可读取“输入区”文本/路径作为参数(上传文件自动修正路径)") gr.Markdown("插件可读取“输入区”文本/路径作为参数(上传文件自动修正路径)")
with gr.Row(elem_id="input-plugin-group"): with gr.Row(elem_id="input-plugin-group"):
plugin_dropdown = gr.Dropdown(choices=crazy_classification, label='', plugin_group_sel = gr.Dropdown(choices=all_plugin_groups, label='', show_label=False, value=DEFAULT_FN_GROUPS,
value=DEFAULT_FN_GROUPS, multiselect=True, interactive=True, elem_classes='normal_mut_select').style(container=False)
multiselect=True, interactive=True,
elem_classes='normal_mut_select',
).style(container=False)
with gr.Row(): with gr.Row():
for role in crazy_fns_role: for k, plugin in plugins.items():
for k in crazy_fns_role[role]: if not plugin.get("AsButton", True): continue
if not crazy_fns_role[role][k].get("AsButton", True): continue visible = True if match_group(plugin['Group'], DEFAULT_FN_GROUPS) else False
if role not in DEFAULT_FN_GROUPS: variant = plugins[k]["Color"] if "Color" in plugin else "secondary"
variant = crazy_fns_role[role][k]["Color"] if "Color" in crazy_fns_role[role][ plugin['Button'] = plugins[k]['Button'] = gr.Button(k, variant=variant, visible=visible).style(size="sm")
k] else "secondary"
crazy_fns_role[role][k]['Button'] = gr.Button(k, variant=variant,
visible=False).style(size="sm")
else:
variant = crazy_fns[k]["Color"] if "Color" in crazy_fns_role[role][
k] else "secondary"
crazy_fns_role[role][k]['Button'] = gr.Button(k, variant=variant,
visible=True).style(size="sm")
with gr.Row(): with gr.Row():
with gr.Accordion("更多函数插件", open=True): with gr.Accordion("更多函数插件", open=True):
dropdown_fn_list = [] dropdown_fn_list = []
for role in crazy_fns_role: for k, plugin in plugins.items():
if role in DEFAULT_FN_GROUPS: if not match_group(plugin['Group'], DEFAULT_FN_GROUPS): continue
for k in crazy_fns_role[role]: if not plugin.get("AsButton", True): dropdown_fn_list.append(k) # 排除已经是按钮的插件
if not crazy_fns_role[role][k].get("AsButton", True): elif plugin.get('AdvancedArgs', False): dropdown_fn_list.append(k) # 对于需要高级参数的插件,亦在下拉菜单中显示
dropdown_fn_list.append(k)
elif crazy_fns_role[role][k].get('AdvancedArgs', False):
dropdown_fn_list.append(k)
with gr.Row(): with gr.Row():
dropdown = gr.Dropdown(dropdown_fn_list, value=r"打开插件列表", label="", show_label=False).style(container=False) dropdown = gr.Dropdown(dropdown_fn_list, value=r"打开插件列表", label="", show_label=False).style(container=False)
with gr.Row(): with gr.Row():
@ -150,6 +134,7 @@ def main():
resetBtn2 = gr.Button("重置", variant="secondary"); resetBtn2.style(size="sm") resetBtn2 = gr.Button("重置", variant="secondary"); resetBtn2.style(size="sm")
stopBtn2 = gr.Button("停止", variant="secondary"); stopBtn2.style(size="sm") stopBtn2 = gr.Button("停止", variant="secondary"); stopBtn2.style(size="sm")
clearBtn2 = gr.Button("清除", variant="secondary", visible=False); clearBtn2.style(size="sm") clearBtn2 = gr.Button("清除", variant="secondary", visible=False); clearBtn2.style(size="sm")
# 功能区显示开关与功能区的互动 # 功能区显示开关与功能区的互动
def fn_area_visibility(a): def fn_area_visibility(a):
ret = {} ret = {}
@ -189,17 +174,17 @@ def main():
# 文件上传区接收文件后与chatbot的互动 # 文件上传区接收文件后与chatbot的互动
file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt, txt2, checkboxes], [chatbot, txt, txt2]) file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt, txt2, checkboxes], [chatbot, txt, txt2])
# 函数插件-固定按钮区 # 函数插件-固定按钮区
for k in crazy_fns: for k in plugins:
if not crazy_fns[k].get("AsButton", True): continue if not plugins[k].get("AsButton", True): continue
click_handle = crazy_fns[k]["Button"].click(ArgsGeneralWrapper(crazy_fns[k]["Function"]), [*input_combo, gr.State(PORT)], output_combo) click_handle = plugins[k]["Button"].click(ArgsGeneralWrapper(plugins[k]["Function"]), [*input_combo, gr.State(PORT)], output_combo)
click_handle.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot]) click_handle.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot])
cancel_handles.append(click_handle) cancel_handles.append(click_handle)
# 函数插件-下拉菜单与随变按钮的互动 # 函数插件-下拉菜单与随变按钮的互动
def on_dropdown_changed(k): def on_dropdown_changed(k):
variant = crazy_fns[k]["Color"] if "Color" in crazy_fns[k] else "secondary" variant = plugins[k]["Color"] if "Color" in plugins[k] else "secondary"
ret = {switchy_bt: gr.update(value=k, variant=variant)} ret = {switchy_bt: gr.update(value=k, variant=variant)}
if crazy_fns[k].get("AdvancedArgs", False): # 是否唤起高级插件参数区 if plugins[k].get("AdvancedArgs", False): # 是否唤起高级插件参数区
ret.update({plugin_advanced_arg: gr.update(visible=True, label=f"插件[{k}]的高级参数说明:" + crazy_fns[k].get("ArgsReminder", [f"没有提供高级参数功能说明"]))}) ret.update({plugin_advanced_arg: gr.update(visible=True, label=f"插件[{k}]的高级参数说明:" + plugins[k].get("ArgsReminder", [f"没有提供高级参数功能说明"]))})
else: else:
ret.update({plugin_advanced_arg: gr.update(visible=False, label=f"插件[{k}]不需要高级参数。")}) ret.update({plugin_advanced_arg: gr.update(visible=False, label=f"插件[{k}]不需要高级参数。")})
return ret return ret
@ -210,35 +195,26 @@ def main():
# 随变按钮的回调函数注册 # 随变按钮的回调函数注册
def route(request: gr.Request, k, *args, **kwargs): def route(request: gr.Request, k, *args, **kwargs):
if k in [r"打开插件列表", r"请先从插件列表中选择"]: return if k in [r"打开插件列表", r"请先从插件列表中选择"]: return
yield from ArgsGeneralWrapper(crazy_fns[k]["Function"])(request, *args, **kwargs) yield from ArgsGeneralWrapper(plugins[k]["Function"])(request, *args, **kwargs)
click_handle = switchy_bt.click(route,[switchy_bt, *input_combo, gr.State(PORT)], output_combo) click_handle = switchy_bt.click(route,[switchy_bt, *input_combo, gr.State(PORT)], output_combo)
click_handle.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot]) click_handle.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot])
cancel_handles.append(click_handle) cancel_handles.append(click_handle)
# 终止按钮的回调函数注册 # 终止按钮的回调函数注册
stopBtn.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles) stopBtn.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
stopBtn2.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles) stopBtn2.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
fn_btn_dict = {crazy_fns_role[role][k]['Button']: {role: k} for role in crazy_fns_role for k in crazy_fns_role[role] if crazy_fns_role[role][k].get('Button')} plugins_as_btn = {name:plugin for name, plugin in plugins.items() if plugin.get('Button', None)}
def show_plugin_btn(plu_list): def on_group_change(group_list):
new_btn_list = [] btn_list = []
fns_list = [] fns_list = []
if not plu_list: if not group_list: # 处理特殊情况:没有选择任何插件组
return [*[fns.update(visible=False) for fns in fn_btn_dict], gr.Dropdown.update(choices=[])] return [*[plugin['Button'].update(visible=False) for _, plugin in plugins_as_btn.items()], gr.Dropdown.update(choices=[])]
else: for k, plugin in plugins.items():
for fns in fn_btn_dict: if plugin.get("AsButton", True):
if list(fn_btn_dict[fns].keys())[0] in plu_list: btn_list.append(plugin['Button'].update(visible=match_group(plugin['Group'], group_list))) # 刷新按钮
new_btn_list.append(fns.update(visible=True)) if plugin.get('AdvancedArgs', False): dropdown_fn_list.append(k) # 对于需要高级参数的插件,亦在下拉菜单中显示
else: elif match_group(plugin['Group'], group_list): fns_list.append(k) # 刷新下拉列表
new_btn_list.append(fns.update(visible=False)) return [*btn_list, gr.Dropdown.update(choices=fns_list)]
for role in crazy_fns_role: plugin_group_sel.select(fn=on_group_change, inputs=[plugin_group_sel], outputs=[*[plugin['Button'] for name, plugin in plugins_as_btn.items()], dropdown])
if role in plu_list:
for k in crazy_fns_role[role]:
if not crazy_fns_role[role][k].get("AsButton", True):
fns_list.append(k)
elif crazy_fns_role[role][k].get('AdvancedArgs', False):
fns_list.append(k)
return [*new_btn_list, gr.Dropdown.update(choices=fns_list)]
plugin_dropdown.select(fn=show_plugin_btn, inputs=[plugin_dropdown],
outputs=[*fn_btn_dict.keys(), dropdown])
if ENABLE_AUDIO: if ENABLE_AUDIO:
from crazy_functions.live_audio.audio_io import RealtimeAudioDistribution from crazy_functions.live_audio.audio_io import RealtimeAudioDistribution
rad = RealtimeAudioDistribution() rad = RealtimeAudioDistribution()
@ -270,8 +246,10 @@ def main():
auto_opentab_delay() auto_opentab_delay()
demo.queue(concurrency_count=CONCURRENT_COUNT).launch( demo.queue(concurrency_count=CONCURRENT_COUNT).launch(
server_name="0.0.0.0", server_port=PORT, server_name="0.0.0.0",
favicon_path="docs/logo.png", auth=AUTHENTICATION, server_port=PORT,
favicon_path="docs/logo.png",
auth=AUTHENTICATION if len(AUTHENTICATION) != 0 else None,
blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile"]) blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile"])
# 如果需要在二级路径下运行 # 如果需要在二级路径下运行