diff --git a/.gitignore b/.gitignore index 6d0e0cce..18fc175b 100644 --- a/.gitignore +++ b/.gitignore @@ -153,6 +153,6 @@ media flagged request_llms/ChatGLM-6b-onnx-u8s8 .pre-commit-config.yaml -themes/common.js.min.*.js test.html -objdump* \ No newline at end of file +objdump* +*.min.*.js \ No newline at end of file diff --git a/main.py b/main.py index a077a20e..d194e403 100644 --- a/main.py +++ b/main.py @@ -30,7 +30,8 @@ def main(): raise ModuleNotFoundError("使用项目内置Gradio获取最优体验! 请运行 `pip install -r requirements.txt` 指令安装内置Gradio及其他依赖, 详情信息见requirements.txt.") from request_llms.bridge_all import predict from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, DummyWith - # 建议您复制一个config_private.py放自己的秘密, 如API和代理网址 + + # 读取配置 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 = get_conf('CHATBOT_HEIGHT', 'LAYOUT', 'AVAIL_LLM_MODELS', 'AUTO_CLEAR_TXT') ENABLE_AUDIO, AUTO_CLEAR_TXT, PATH_LOGGING, AVAIL_THEMES, THEME, ADD_WAIFU = get_conf('ENABLE_AUDIO', 'AUTO_CLEAR_TXT', 'PATH_LOGGING', 'AVAIL_THEMES', 'THEME', 'ADD_WAIFU') @@ -42,7 +43,7 @@ def main(): PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT from check_proxy import get_current_version from themes.theme import adjust_theme, advanced_css, theme_declaration, js_code_clear, js_code_reset, js_code_show_or_hide, js_code_show_or_hide_group2 - from themes.theme import js_code_for_css_changing, js_code_for_toggle_darkmode, js_code_for_persistent_cookie_init + from themes.theme import js_code_for_toggle_darkmode, js_code_for_persistent_cookie_init from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, assign_user_uuid title_html = f"

GPT 学术优化 {get_current_version()}

{theme_declaration}" @@ -70,6 +71,7 @@ def main(): from check_proxy import check_proxy, auto_update, warm_up_modules proxy_info = check_proxy(proxies) + # 切换布局 gr_L1 = lambda: gr.Row().style() gr_L2 = lambda scale, elem_id: gr.Column(scale=scale, elem_id=elem_id, min_width=400) if LAYOUT == "TOP-DOWN": @@ -154,14 +156,17 @@ def main(): with gr.Accordion("点击展开“文件下载区”。", open=False) as area_file_up: file_upload = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload") + # 左上角工具栏定义 from themes.gui_toolbar import define_gui_toolbar checkboxes, checkboxes_2, max_length_sl, theme_dropdown, system_prompt, file_upload_2, md_dropdown, top_p, temperature = \ define_gui_toolbar(AVAIL_LLM_MODELS, LLM_MODEL, INIT_SYS_PROMPT, THEME, AVAIL_THEMES, ADD_WAIFU, help_menu_description, js_code_for_toggle_darkmode) + # 浮动菜单定义 from themes.gui_floating_menu import define_gui_floating_menu area_input_secondary, txt2, area_customize, submitBtn2, resetBtn2, clearBtn2, stopBtn2 = \ define_gui_floating_menu(customize_btns, functional, predefined_btns, cookies, web_cookie_cache) + # 插件二级菜单的实现 from themes.gui_advanced_plugin_class import define_gui_advanced_plugin_class new_plugin_callback, route_switchy_bt_with_arg, usr_confirmed_arg = \ define_gui_advanced_plugin_class(plugins) @@ -233,6 +238,7 @@ def main(): plugin_["Label"] = f"插件[{k}]不需要高级参数。" return to_cookie_str(plugin_) + # 插件的注册(前端代码注册) for k in plugins: register_advanced_plugin_init_arr += f"""register_plugin_init("{k}","{encode_plugin_info(k, plugins[k])}");""" if plugins[k].get("Class", None): @@ -242,19 +248,18 @@ def main(): if plugins[k].get("Class", None) is None: assert plugins[k].get("Function", None) is not None click_handle = plugins[k]["Button"].click(None, inputs=[], outputs=None, _js=f"""()=>run_classic_plugin_via_id("{plugins[k]["ButtonElemId"]}")""") - # click_handle = plugins[k]["Button"].click(ArgsGeneralWrapper(plugins[k]["Function"]), [*input_combo], output_combo) - # click_handle.then(on_report_generated, [cookies, file_upload, chatbot], [cookies, file_upload, chatbot]).then(None, [plugins[k]["Button"]], None, _js=r"(fn)=>on_plugin_exe_complete(fn)") - # cancel_handles.append(click_handle) else: click_handle = plugins[k]["Button"].click(None, inputs=[], outputs=None, _js=f"""()=>run_advanced_plugin_launch_code("{k}")""") # 函数插件-下拉菜单与随变按钮的互动(新版-更流畅) dropdown.select(None, [dropdown], None, _js=f"""(dropdown)=>run_dropdown_shift(dropdown)""") + # 模型切换时的回调 def on_md_dropdown_changed(k): return {chatbot: gr.update(label="当前模型:"+k)} md_dropdown.select(on_md_dropdown_changed, [md_dropdown], [chatbot]) + # 主题修改 def on_theme_dropdown_changed(theme, secret_css): adjust_theme, css_part1, _, adjust_dynamic_theme = load_dynamic_theme(theme) if adjust_dynamic_theme: @@ -262,9 +267,8 @@ def main(): else: css_part2 = adjust_theme()._get_theme_css() return css_part2 + css_part1 - - theme_handle = theme_dropdown.select(on_theme_dropdown_changed, [theme_dropdown, secret_css], [secret_css]) - theme_handle.then(None, [secret_css], None, _js=js_code_for_css_changing) + theme_handle = theme_dropdown.select(on_theme_dropdown_changed, [theme_dropdown, secret_css], [secret_css]) # , _js="""change_theme_prepare""") + theme_handle.then(None, [theme_dropdown, secret_css], None, _js="""change_theme""") switchy_bt.click(None, [switchy_bt], None, _js="(switchy_bt)=>on_flex_button_click(switchy_bt)") # 随变按钮的回调函数注册 @@ -302,6 +306,8 @@ def main(): elif match_group(plugin['Group'], group_list): fns_list.append(k) # 刷新下拉列表 return [*btn_list, gr.Dropdown.update(choices=fns_list)] 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 ENABLE_AUDIO: from crazy_functions.live_audio.audio_io import RealtimeAudioDistribution rad = RealtimeAudioDistribution() @@ -309,18 +315,18 @@ def main(): rad.feed(cookies['uuid'].hex, audio) audio_mic.stream(deal_audio, inputs=[audio_mic, cookies]) - + # 生成当前浏览器窗口的uuid(刷新失效) app_block.load(assign_user_uuid, inputs=[cookies], outputs=[cookies]) + # 初始化(前端) from shared_utils.cookie_manager import load_web_cookie_cache__fn_builder load_web_cookie_cache = load_web_cookie_cache__fn_builder(customize_btns, cookies, predefined_btns) app_block.load(load_web_cookie_cache, inputs = [web_cookie_cache, cookies], outputs = [web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()], _js=js_code_for_persistent_cookie_init) - app_block.load(None, inputs=[], outputs=None, _js=f"""()=>GptAcademicJavaScriptInit("{DARK_MODE}","{INIT_SYS_PROMPT}","{ADD_WAIFU}","{LAYOUT}","{TTS_TYPE}")""") # 配置暗色主题或亮色主题 app_block.load(None, inputs=[], outputs=None, _js="""()=>{REP}""".replace("REP", register_advanced_plugin_init_arr)) - # gradio的inbrowser触发不太稳定,回滚代码到原始的浏览器打开函数 + # Gradio的inbrowser触发不太稳定,回滚代码到原始的浏览器打开函数 def run_delayed_tasks(): import threading, webbrowser, time print(f"如果浏览器没有自动打开,请复制并转到以下URL:") diff --git a/themes/common.js b/themes/common.js index 5b69c0ce..e7a14ce4 100644 --- a/themes/common.js +++ b/themes/common.js @@ -1,3 +1,6 @@ +// 标志位 +enable_tts = false; + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // 第 1 部分: 工具函数 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= @@ -914,131 +917,6 @@ function gpt_academic_gradio_saveload( } } -enable_tts = false; -async function GptAcademicJavaScriptInit(dark, prompt, live2d, layout, tts) { - // 第一部分,布局初始化 - audio_fn_init(); - minor_ui_adjustment(); - chatbotIndicator = gradioApp().querySelector('#gpt-chatbot > div.wrap'); - var chatbotObserver = new MutationObserver(() => { - chatbotContentChanged(1); - }); - chatbotObserver.observe(chatbotIndicator, { attributes: true, childList: true, subtree: true }); - if (layout === "LEFT-RIGHT") { chatbotAutoHeight(); } - if (layout === "LEFT-RIGHT") { limit_scroll_position(); } - - // 第二部分,读取Cookie,初始话界面 - let searchString = ""; - let bool_value = ""; - // darkmode 深色模式 - if (getCookie("js_darkmode_cookie")) { - dark = getCookie("js_darkmode_cookie") - } - dark = dark == "True"; - if (document.querySelectorAll('.dark').length) { - if (!dark) { - document.querySelectorAll('.dark').forEach(el => el.classList.remove('dark')); - } - } else { - if (dark) { - document.querySelector('body').classList.add('dark'); - } - } - - // 自动朗读 - if (tts != "DISABLE"){ - enable_tts = true; - if (getCookie("js_auto_read_cookie")) { - auto_read_tts = getCookie("js_auto_read_cookie") - auto_read_tts = auto_read_tts == "True"; - if (auto_read_tts) { - allow_auto_read_tts_flag = true; - } - } - } - - // SysPrompt 系统静默提示词 - gpt_academic_gradio_saveload("load", "elem_prompt", "js_system_prompt_cookie", null, "str"); - // Temperature 大模型温度参数 - gpt_academic_gradio_saveload("load", "elem_temperature", "js_temperature_cookie", null, "float"); - // md_dropdown 大模型类型选择 - if (getCookie("js_md_dropdown_cookie")) { - const cached_model = getCookie("js_md_dropdown_cookie"); - var model_sel = await get_gradio_component("elem_model_sel"); - // determine whether the cached model is in the choices - if (model_sel.props.choices.includes(cached_model)){ - // change dropdown - gpt_academic_gradio_saveload("load", "elem_model_sel", "js_md_dropdown_cookie", null, "str"); - // 连锁修改chatbot的label - push_data_to_gradio_component({ - label: '当前模型:' + getCookie("js_md_dropdown_cookie"), - __type__: 'update' - }, "gpt-chatbot", "obj") - } - } - - - - // clearButton 自动清除按钮 - if (getCookie("js_clearbtn_show_cookie")) { - // have cookie - bool_value = getCookie("js_clearbtn_show_cookie") - bool_value = bool_value == "True"; - searchString = "输入清除键"; - - if (bool_value) { - // make btns appear - let clearButton = document.getElementById("elem_clear"); clearButton.style.display = "block"; - let clearButton2 = document.getElementById("elem_clear2"); clearButton2.style.display = "block"; - // deal with checkboxes - let arr_with_clear_btn = update_array( - await get_data_from_gradio_component('cbs'), "输入清除键", "add" - ) - push_data_to_gradio_component(arr_with_clear_btn, "cbs", "no_conversion"); - } else { - // make btns disappear - let clearButton = document.getElementById("elem_clear"); clearButton.style.display = "none"; - let clearButton2 = document.getElementById("elem_clear2"); clearButton2.style.display = "none"; - // deal with checkboxes - let arr_without_clear_btn = update_array( - await get_data_from_gradio_component('cbs'), "输入清除键", "remove" - ) - push_data_to_gradio_component(arr_without_clear_btn, "cbs", "no_conversion"); - } - } - - // live2d 显示 - if (getCookie("js_live2d_show_cookie")) { - // have cookie - searchString = "添加Live2D形象"; - bool_value = getCookie("js_live2d_show_cookie"); - bool_value = bool_value == "True"; - if (bool_value) { - loadLive2D(); - let arr_with_live2d = update_array( - await get_data_from_gradio_component('cbsc'), "添加Live2D形象", "add" - ) - push_data_to_gradio_component(arr_with_live2d, "cbsc", "no_conversion"); - } else { - try { - $('.waifu').hide(); - let arr_without_live2d = update_array( - await get_data_from_gradio_component('cbsc'), "添加Live2D形象", "remove" - ) - push_data_to_gradio_component(arr_without_live2d, "cbsc", "no_conversion"); - } catch (error) { - } - } - } else { - // do not have cookie - if (live2d) { - loadLive2D(); - } else { - } - } - -} - function reset_conversation(a, b) { // console.log("js_code_reset"); diff --git a/themes/common.py b/themes/common.py index 50a9e6e4..9b5e8e48 100644 --- a/themes/common.py +++ b/themes/common.py @@ -1,3 +1,4 @@ +from functools import cache from toolbox import get_conf CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf("CODE_HIGHLIGHT", "ADD_WAIFU", "LAYOUT") @@ -23,22 +24,30 @@ def minimize_js(common_js_path): except: return common_js_path +@cache def get_common_html_javascript_code(): js = "\n" - common_js_path = "themes/common.js" - minimized_js_path = minimize_js(common_js_path) - for jsf in [ - f"file={minimized_js_path}", - ]: - js += f"""\n""" + common_js_path_list = [ + "themes/common.js", + "themes/theme.js", + "themes/init.js", + ] - # 添加Live2D - if ADD_WAIFU: + if ADD_WAIFU: # 添加Live2D + common_js_path_list += [ + "themes/waifu_plugin/jquery.min.js", + "themes/waifu_plugin/jquery-ui.min.js", + ] + + for common_js_path in common_js_path_list: + if '.min.' not in common_js_path: + minimized_js_path = minimize_js(common_js_path) for jsf in [ - "file=themes/waifu_plugin/jquery.min.js", - "file=themes/waifu_plugin/jquery-ui.min.js", + f"file={minimized_js_path}", ]: js += f"""\n""" - else: + + if not ADD_WAIFU: js += """\n""" + return js diff --git a/themes/init.js b/themes/init.js new file mode 100644 index 00000000..0f5711bb --- /dev/null +++ b/themes/init.js @@ -0,0 +1,125 @@ +async function GptAcademicJavaScriptInit(dark, prompt, live2d, layout, tts) { + // 第一部分,布局初始化 + audio_fn_init(); + minor_ui_adjustment(); + chatbotIndicator = gradioApp().querySelector('#gpt-chatbot > div.wrap'); + var chatbotObserver = new MutationObserver(() => { + chatbotContentChanged(1); + }); + chatbotObserver.observe(chatbotIndicator, { attributes: true, childList: true, subtree: true }); + if (layout === "LEFT-RIGHT") { chatbotAutoHeight(); } + if (layout === "LEFT-RIGHT") { limit_scroll_position(); } + + // 第二部分,读取Cookie,初始话界面 + let searchString = ""; + let bool_value = ""; + // darkmode 深色模式 + if (getCookie("js_darkmode_cookie")) { + dark = getCookie("js_darkmode_cookie") + } + dark = dark == "True"; + if (document.querySelectorAll('.dark').length) { + if (!dark) { + document.querySelectorAll('.dark').forEach(el => el.classList.remove('dark')); + } + } else { + if (dark) { + document.querySelector('body').classList.add('dark'); + } + } + + // 自动朗读 + if (tts != "DISABLE"){ + enable_tts = true; + if (getCookie("js_auto_read_cookie")) { + auto_read_tts = getCookie("js_auto_read_cookie") + auto_read_tts = auto_read_tts == "True"; + if (auto_read_tts) { + allow_auto_read_tts_flag = true; + } + } + } + + // SysPrompt 系统静默提示词 + gpt_academic_gradio_saveload("load", "elem_prompt", "js_system_prompt_cookie", null, "str"); + // Temperature 大模型温度参数 + gpt_academic_gradio_saveload("load", "elem_temperature", "js_temperature_cookie", null, "float"); + // md_dropdown 大模型类型选择 + if (getCookie("js_md_dropdown_cookie")) { + const cached_model = getCookie("js_md_dropdown_cookie"); + var model_sel = await get_gradio_component("elem_model_sel"); + // determine whether the cached model is in the choices + if (model_sel.props.choices.includes(cached_model)){ + // change dropdown + gpt_academic_gradio_saveload("load", "elem_model_sel", "js_md_dropdown_cookie", null, "str"); + // 连锁修改chatbot的label + push_data_to_gradio_component({ + label: '当前模型:' + getCookie("js_md_dropdown_cookie"), + __type__: 'update' + }, "gpt-chatbot", "obj") + } + } + + + + // clearButton 自动清除按钮 + if (getCookie("js_clearbtn_show_cookie")) { + // have cookie + bool_value = getCookie("js_clearbtn_show_cookie") + bool_value = bool_value == "True"; + searchString = "输入清除键"; + + if (bool_value) { + // make btns appear + let clearButton = document.getElementById("elem_clear"); clearButton.style.display = "block"; + let clearButton2 = document.getElementById("elem_clear2"); clearButton2.style.display = "block"; + // deal with checkboxes + let arr_with_clear_btn = update_array( + await get_data_from_gradio_component('cbs'), "输入清除键", "add" + ) + push_data_to_gradio_component(arr_with_clear_btn, "cbs", "no_conversion"); + } else { + // make btns disappear + let clearButton = document.getElementById("elem_clear"); clearButton.style.display = "none"; + let clearButton2 = document.getElementById("elem_clear2"); clearButton2.style.display = "none"; + // deal with checkboxes + let arr_without_clear_btn = update_array( + await get_data_from_gradio_component('cbs'), "输入清除键", "remove" + ) + push_data_to_gradio_component(arr_without_clear_btn, "cbs", "no_conversion"); + } + } + + // live2d 显示 + if (getCookie("js_live2d_show_cookie")) { + // have cookie + searchString = "添加Live2D形象"; + bool_value = getCookie("js_live2d_show_cookie"); + bool_value = bool_value == "True"; + if (bool_value) { + loadLive2D(); + let arr_with_live2d = update_array( + await get_data_from_gradio_component('cbsc'), "添加Live2D形象", "add" + ) + push_data_to_gradio_component(arr_with_live2d, "cbsc", "no_conversion"); + } else { + try { + $('.waifu').hide(); + let arr_without_live2d = update_array( + await get_data_from_gradio_component('cbsc'), "添加Live2D形象", "remove" + ) + push_data_to_gradio_component(arr_without_live2d, "cbsc", "no_conversion"); + } catch (error) { + } + } + } else { + // do not have cookie + if (live2d) { + loadLive2D(); + } else { + } + } + + // 主题加载(恢复到上次) + change_theme("", "") +} diff --git a/themes/theme.js b/themes/theme.js new file mode 100644 index 00000000..a0cd5278 --- /dev/null +++ b/themes/theme.js @@ -0,0 +1,41 @@ +async function try_load_previous_theme(){ + if (getCookie("js_theme_selection_cookie")) { + theme_selection = getCookie("js_theme_selection_cookie"); + let css = localStorage.getItem('theme-' + theme_selection); + if (css) { + change_theme(theme_selection, css); + } + } +} + +async function change_theme(theme_selection, css) { + if (theme_selection.length==0) { + try_load_previous_theme(); + return; + } + + var existingStyles = document.querySelectorAll("body > gradio-app > div > style") + for (var i = 0; i < existingStyles.length; i++) { + var style = existingStyles[i]; + style.parentNode.removeChild(style); + } + var existingStyles = document.querySelectorAll("style[data-loaded-css]"); + for (var i = 0; i < existingStyles.length; i++) { + var style = existingStyles[i]; + style.parentNode.removeChild(style); + } + + setCookie("js_theme_selection_cookie", theme_selection, 3); + localStorage.setItem('theme-' + theme_selection, css); + + var styleElement = document.createElement('style'); + styleElement.setAttribute('data-loaded-css', 'placeholder'); + styleElement.innerHTML = css; + document.body.appendChild(styleElement); +} + + +// // 记录本次的主题切换 +// async function change_theme_prepare(theme_selection, secret_css) { +// setCookie("js_theme_selection_cookie", theme_selection, 3); +// } \ No newline at end of file diff --git a/themes/theme.py b/themes/theme.py index e0417871..28195774 100644 --- a/themes/theme.py +++ b/themes/theme.py @@ -71,29 +71,10 @@ def from_cookie_str(c): """ -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 第 3 部分 -内嵌的javascript代码 +内嵌的javascript代码(这部分代码会逐渐移动到common.js中) -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- """ -js_code_for_css_changing = """(css) => { - var existingStyles = document.querySelectorAll("body > gradio-app > div > style") - for (var i = 0; i < existingStyles.length; i++) { - var style = existingStyles[i]; - style.parentNode.removeChild(style); - } - var existingStyles = document.querySelectorAll("style[data-loaded-css]"); - for (var i = 0; i < existingStyles.length; i++) { - var style = existingStyles[i]; - style.parentNode.removeChild(style); - } - var styleElement = document.createElement('style'); - styleElement.setAttribute('data-loaded-css', 'placeholder'); - styleElement.innerHTML = css; - document.body.appendChild(styleElement); -} -""" - - js_code_for_toggle_darkmode = """() => { if (document.querySelectorAll('.dark').length) { setCookie("js_darkmode_cookie", "False", 365);