From e9a7f9439fbea4c0b1a8a574160e99e7f44a8397 Mon Sep 17 00:00:00 2001 From: binary-husky Date: Sat, 7 Dec 2024 15:59:30 +0800 Subject: [PATCH 01/14] upgrade gradio --- main.py | 20 +-- shared_utils/cookie_manager.py | 32 +++-- themes/common.js | 221 +++++++++++++++++++++++++-------- themes/gui_floating_menu.py | 4 +- themes/init.js | 2 + themes/theme.py | 9 -- themes/welcome.js | 84 ++++++------- toolbox.py | 12 +- 8 files changed, 255 insertions(+), 129 deletions(-) diff --git a/main.py b/main.py index dd23d49b..e54f6d9a 100644 --- a/main.py +++ b/main.py @@ -34,7 +34,7 @@ def encode_plugin_info(k, plugin)->str: def main(): import gradio as gr - if gr.__version__ not in ['3.32.9', '3.32.10', '3.32.11']: + if gr.__version__ not in ['3.32.12']: raise ModuleNotFoundError("使用项目内置Gradio获取最优体验! 请运行 `pip install -r requirements.txt` 指令安装内置Gradio及其他依赖, 详情信息见requirements.txt.") # 一些基础工具 @@ -57,7 +57,7 @@ def main(): # 如果WEB_PORT是-1, 则随机选取WEB端口 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 adjust_theme, advanced_css, theme_declaration, js_code_clear, js_code_show_or_hide, js_code_show_or_hide_group2 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}" @@ -106,7 +106,7 @@ def main(): with gr_L2(scale=2, elem_id="gpt-chat"): chatbot = gr.Chatbot(label=f"当前模型:{LLM_MODEL}", elem_id="gpt-chatbot") if LAYOUT == "TOP-DOWN": chatbot.style(height=CHATBOT_HEIGHT) - history, history_cache, history_cache_update = make_history_cache() # 定义 后端state(history)、前端(history_cache)、后端setter(history_cache_update)三兄弟 + history, _, _ = make_history_cache() # 定义 后端state(history)、前端(history_cache)、后端setter(history_cache_update)三兄弟 with gr_L2(scale=1, elem_id="gpt-panel"): with gr.Accordion("输入区", open=True, elem_id="input-panel") as area_input_primary: with gr.Row(): @@ -174,6 +174,7 @@ 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 = \ @@ -183,6 +184,9 @@ def main(): from themes.gui_floating_menu import define_gui_floating_menu area_input_secondary, txt2, area_customize, _, resetBtn2, clearBtn2, stopBtn2 = \ define_gui_floating_menu(customize_btns, functional, predefined_btns, cookies, web_cookie_cache) + + # 浮动时间线定义 + gr.Spark(label="", value="") # 插件二级菜单的实现 from themes.gui_advanced_plugin_class import define_gui_advanced_plugin_class @@ -222,11 +226,11 @@ def main(): multiplex_sel.select( None, [multiplex_sel], None, _js=f"""(multiplex_sel)=>run_multiplex_shift(multiplex_sel)""") cancel_handles.append(submit_btn.click(**predict_args)) - resetBtn.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status - resetBtn2.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status - reset_server_side_args = (lambda history: ([], [], "已重置", json.dumps(history)), [history], [chatbot, history, status, history_cache]) - resetBtn.click(*reset_server_side_args) # 再在后端清除history,把history转存history_cache备用 - resetBtn2.click(*reset_server_side_args) # 再在后端清除history,把history转存history_cache备用 + resetBtn.click(None, None, [chatbot, history, status], _js="""(a,b,c)=>clear_conversation(a,b,c)""") # 先在前端快速清除chatbot&status + resetBtn2.click(None, None, [chatbot, history, status], _js="""(a,b,c)=>clear_conversation(a,b,c)""") # 先在前端快速清除chatbot&status + # reset_server_side_args = (lambda history: ([], [], "已重置"), [history], [chatbot, history, status]) + # resetBtn.click(*reset_server_side_args) # 再在后端清除history + # resetBtn2.click(*reset_server_side_args) # 再在后端清除history clearBtn.click(None, None, [txt, txt2], _js=js_code_clear) clearBtn2.click(None, None, [txt, txt2], _js=js_code_clear) if AUTO_CLEAR_TXT: diff --git a/shared_utils/cookie_manager.py b/shared_utils/cookie_manager.py index 88fe3a91..d503ce77 100644 --- a/shared_utils/cookie_manager.py +++ b/shared_utils/cookie_manager.py @@ -77,16 +77,28 @@ def make_history_cache(): # 定义 后端state(history)、前端(history_cache)、后端setter(history_cache_update)三兄弟 import gradio as gr # 定义history的后端state - history = gr.State([]) - # 定义history的一个孪生的前端存储区(隐藏) - history_cache = gr.Textbox(visible=False, elem_id="history_cache") - # 定义history_cache->history的更新方法(隐藏)。在触发这个按钮时,会先执行js代码更新history_cache,然后再执行python代码更新history - def process_history_cache(history_cache): - return json.loads(history_cache) - # 另一种更简单的setter方法 - history_cache_update = gr.Button("", elem_id="elem_update_history", visible=False).click( - process_history_cache, inputs=[history_cache], outputs=[history]) - return history, history_cache, history_cache_update + # history = gr.State([]) + history = gr.Textbox(visible=False, elem_id="history-ng") + # # 定义history的一个孪生的前端存储区(隐藏) + # history_cache = gr.Textbox(visible=False, elem_id="history_cache") + # # 定义history_cache->history的更新方法(隐藏)。在触发这个按钮时,会先执行js代码更新history_cache,然后再执行python代码更新history + # def process_history_cache(history_cache): + # return json.loads(history_cache) + # # 另一种更简单的setter方法 + # history_cache_update = gr.Button("", elem_id="elem_update_history", visible=False).click( + # process_history_cache, inputs=[history_cache], outputs=[history]) + # # save history to history_cache + # def process_history_cache(history_cache): + # return json.dumps(history_cache) + # # 定义history->history_cache的更新方法(隐藏) + # def sync_history_cache(history): + # print("sync_history_cache", history) + # return json.dumps(history) + # # history.change(sync_history_cache, inputs=[history], outputs=[history_cache]) + + # # history_cache_sync = gr.Button("", elem_id="elem_sync_history", visible=False).click( + # # lambda history: (json.dumps(history)), inputs=[history_cache], outputs=[history]) + return history, None, None diff --git a/themes/common.js b/themes/common.js index c0b794cf..55727cc6 100644 --- a/themes/common.js +++ b/themes/common.js @@ -318,7 +318,7 @@ function addCopyButton(botElement, index, is_last_in_arr) { } }); - if (enable_tts){ + if (enable_tts) { var audioButton = document.createElement('button'); audioButton.classList.add('audio-toggle-btn'); audioButton.innerHTML = audioIcon; @@ -346,7 +346,7 @@ function addCopyButton(botElement, index, is_last_in_arr) { var messageBtnColumn = document.createElement('div'); messageBtnColumn.classList.add('message-btn-row'); messageBtnColumn.appendChild(copyButton); - if (enable_tts){ + if (enable_tts) { messageBtnColumn.appendChild(audioButton); } botElement.appendChild(messageBtnColumn); @@ -391,6 +391,8 @@ function chatbotContentChanged(attempt = 1, force = false) { // Now pass both the message element and the is_last_in_arr boolean to addCopyButton addCopyButton(message, index, is_last_in_arr); + + save_conversation_history(); }); // gradioApp().querySelectorAll('#gpt-chatbot .message-wrap .message.bot').forEach(addCopyButton); }, i === 0 ? 0 : 200); @@ -854,8 +856,7 @@ function limit_scroll_position() { // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= function loadLive2D() { - if (document.querySelector(".waifu") ) - { + if (document.querySelector(".waifu")) { $('.waifu').show(); } else { try { @@ -937,22 +938,140 @@ function gpt_academic_gradio_saveload( } } +function update_conversation_metadata() { + // Create a conversation UUID and timestamp + const conversationId = crypto.randomUUID(); + const timestamp = new Date().toISOString(); + const conversationData = { + id: conversationId, + timestamp: timestamp + }; + // Save to cookie + setCookie("conversation_metadata", JSON.stringify(conversationData), 2); + // read from cookie + let conversation_metadata = getCookie("conversation_metadata"); + console.log("conversation_metadata", conversation_metadata); +} + +// // Example schema for conversation data structure +// const example_conversation = { +// metadata: { +// id: "550e8400-e29b-41d4-a716-446655440000", +// timestamp: "2024-03-29T12:34:56.789Z" +// }, +// conversation: [ +// ["user", "Hello, how are you?"], +// ["assistant", "I'm doing well, thank you for asking! How can I help you today?"], +// ["user", "What is the weather like?"], +// ["assistant", "I don't have access to real-time weather information. You would need to check a weather service or look outside to know the current weather conditions."] +// ], +// preview: "A conversation about greetings and weather" +// } + +// Helper function to generate conversation preview +function generatePreview(conversation, maxLength = 100) { + if (!conversation || conversation.length === 0) return ""; + // Join all messages with dash separator + const preview = conversation.join("\n"); + if (preview.length <= maxLength) return preview; + return preview.substring(0, maxLength) + "..."; +} + +async function save_conversation_history() { + // 505030475 + let chatbot = await get_data_from_gradio_component('gpt-chatbot'); + let history = await get_data_from_gradio_component('history-ng'); + let conversation_metadata = getCookie("conversation_metadata"); + conversation_metadata = JSON.parse(conversation_metadata); + // console.log("conversation_metadata", conversation_metadata); + let conversation = { + timestamp: conversation_metadata.timestamp, + id: conversation_metadata.id, + metadata: conversation_metadata, + conversation: chatbot, + history: history, + preview: generatePreview(JSON.parse(history)) + }; + + // Get existing conversation history from local storage + let conversation_history = []; + try { + const stored = localStorage.getItem('conversation_history'); + if (stored) { + conversation_history = JSON.parse(stored); + } + } catch (e) { + // console.error('Error reading conversation history from localStorage:', e); + } + + // Find existing conversation with same ID + const existingIndex = conversation_history.findIndex(c => c.id === conversation.id); + + if (existingIndex >= 0) { + // Update existing conversation + conversation_history[existingIndex] = conversation; + } else { + // Add new conversation + conversation_history.push(conversation); + } + + // Sort conversations by timestamp, newest first + conversation_history.sort((a, b) => { + const timeA = new Date(a.timestamp).getTime(); + const timeB = new Date(b.timestamp).getTime(); + return timeB - timeA; + }); + + // Save back to local storage + try { + localStorage.setItem('conversation_history', JSON.stringify(conversation_history)); + const LOCAL_STORAGE_UPDATED = "gptac_conversation_history_updated"; + window.dispatchEvent( + new CustomEvent(LOCAL_STORAGE_UPDATED, { + detail: conversation_history + }) + ); + } catch (e) { + console.error('Error saving conversation history to localStorage:', e); + } +} + +function restore_chat_from_local_storage(event) { + let conversation = event.detail; + push_data_to_gradio_component(conversation.conversation, "gpt-chatbot", "obj"); + push_data_to_gradio_component(conversation.history, "history-ng", "obj"); + console.log("restore_chat_from_local_storage", conversation); +} + + +function clear_conversation(a, b, c) { + update_conversation_metadata(); + let stopButton = document.getElementById("elem_stop"); + stopButton.click(); + // console.log("clear_conversation"); + return reset_conversation(a, b); +} function reset_conversation(a, b) { // console.log("js_code_reset"); a = btoa(unescape(encodeURIComponent(JSON.stringify(a)))); setCookie("js_previous_chat_cookie", a, 1); + b = btoa(unescape(encodeURIComponent(JSON.stringify(b)))); + setCookie("js_previous_history_cookie", b, 1); gen_restore_btn(); return [[], [], "已重置"]; } // clear -> 将 history 缓存至 history_cache -> 点击复原 -> restore_previous_chat() -> 触发elem_update_history -> 读取 history_cache function restore_previous_chat() { - console.log("restore_previous_chat"); + // console.log("restore_previous_chat"); let chat = getCookie("js_previous_chat_cookie"); chat = JSON.parse(decodeURIComponent(escape(atob(chat)))); push_data_to_gradio_component(chat, "gpt-chatbot", "obj"); - document.querySelector("#elem_update_history").click(); // in order to call set_history_gr_state, and send history state to server + let history = getCookie("js_previous_history_cookie"); + history = JSON.parse(decodeURIComponent(escape(atob(history)))); + push_data_to_gradio_component(history, "history-ng", "obj"); + // document.querySelector("#elem_update_history").click(); // in order to call set_history_gr_state, and send history state to server } function gen_restore_btn() { @@ -1010,8 +1129,7 @@ function gen_restore_btn() { `; // only add when not exist - if (!document.getElementById('recvButtonStyle')) - { + if (!document.getElementById('recvButtonStyle')) { document.head.appendChild(styleSheet); } @@ -1033,8 +1151,7 @@ function gen_restore_btn() { document.body.removeChild(this); }); // only add when not exist - if (!document.getElementById('recvButton')) - { + if (!document.getElementById('recvButton')) { document.body.appendChild(button); } @@ -1043,7 +1160,7 @@ function gen_restore_btn() { } async function on_plugin_exe_complete(fn_name) { - console.log(fn_name); + // console.log(fn_name); if (fn_name === "保存当前的对话") { // get chat profile path let chatbot = await get_data_from_gradio_component('gpt-chatbot'); @@ -1070,7 +1187,7 @@ async function on_plugin_exe_complete(fn_name) { } -async function generate_menu(guiBase64String, btnName){ +async function generate_menu(guiBase64String, btnName) { // assign the button and menu data push_data_to_gradio_component(guiBase64String, "invisible_current_pop_up_plugin_arg", "string"); push_data_to_gradio_component(btnName, "invisible_callback_btn_for_plugin_exe", "string"); @@ -1104,22 +1221,22 @@ async function generate_menu(guiBase64String, btnName){ /////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////// Textbox //////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// - if (gui_args[key].type=='string'){ // PLUGIN_ARG_MENU + if (gui_args[key].type == 'string') { // PLUGIN_ARG_MENU const component_name = "plugin_arg_txt_" + text_cnt; push_data_to_gradio_component({ visible: true, - label: gui_args[key].title + "(" + gui_args[key].description + ")", + label: gui_args[key].title + "(" + gui_args[key].description + ")", // label: gui_args[key].title, placeholder: gui_args[key].description, __type__: 'update' }, component_name, "obj"); - if (key === "main_input"){ + if (key === "main_input") { // 为了与旧插件兼容,生成菜单时,自动加载输入栏的值 let current_main_input = await get_data_from_gradio_component('user_input_main'); let current_main_input_2 = await get_data_from_gradio_component('user_input_float'); push_data_to_gradio_component(current_main_input + current_main_input_2, component_name, "obj"); } - else if (key === "advanced_arg"){ + else if (key === "advanced_arg") { // 为了与旧插件兼容,生成菜单时,自动加载旧高级参数输入区的值 let advance_arg_input_legacy = await get_data_from_gradio_component('advance_arg_input_legacy'); push_data_to_gradio_component(advance_arg_input_legacy, component_name, "obj"); @@ -1134,12 +1251,12 @@ async function generate_menu(guiBase64String, btnName){ /////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////// Dropdown //////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// - if (gui_args[key].type=='dropdown'){ // PLUGIN_ARG_MENU + if (gui_args[key].type == 'dropdown') { // PLUGIN_ARG_MENU const component_name = "plugin_arg_drop_" + dropdown_cnt; push_data_to_gradio_component({ visible: true, choices: gui_args[key].options, - label: gui_args[key].title + "(" + gui_args[key].description + ")", + label: gui_args[key].title + "(" + gui_args[key].description + ")", // label: gui_args[key].title, placeholder: gui_args[key].description, __type__: 'update' @@ -1154,7 +1271,7 @@ async function generate_menu(guiBase64String, btnName){ } } -async function execute_current_pop_up_plugin(){ +async function execute_current_pop_up_plugin() { let guiBase64String = await get_data_from_gradio_component('invisible_current_pop_up_plugin_arg'); const stringData = atob(guiBase64String); let guiJsonData = JSON.parse(stringData); @@ -1170,8 +1287,8 @@ async function execute_current_pop_up_plugin(){ let text_cnt = 0; for (const key in gui_args) { if (gui_args.hasOwnProperty(key)) { - if (gui_args[key].type=='string'){ // PLUGIN_ARG_MENU - corrisponding_elem_id = "plugin_arg_txt_"+text_cnt + if (gui_args[key].type == 'string') { // PLUGIN_ARG_MENU + corrisponding_elem_id = "plugin_arg_txt_" + text_cnt gui_args[key].user_confirmed_value = await get_data_from_gradio_component(corrisponding_elem_id); text_cnt += 1; } @@ -1180,8 +1297,8 @@ async function execute_current_pop_up_plugin(){ let dropdown_cnt = 0; for (const key in gui_args) { if (gui_args.hasOwnProperty(key)) { - if (gui_args[key].type=='dropdown'){ // PLUGIN_ARG_MENU - corrisponding_elem_id = "plugin_arg_drop_"+dropdown_cnt + if (gui_args[key].type == 'dropdown') { // PLUGIN_ARG_MENU + corrisponding_elem_id = "plugin_arg_drop_" + dropdown_cnt gui_args[key].user_confirmed_value = await get_data_from_gradio_component(corrisponding_elem_id); dropdown_cnt += 1; } @@ -1200,29 +1317,29 @@ async function execute_current_pop_up_plugin(){ } -function hide_all_elem(){ - // PLUGIN_ARG_MENU - for (text_cnt = 0; text_cnt < 8; text_cnt++){ +function hide_all_elem() { + // PLUGIN_ARG_MENU + for (text_cnt = 0; text_cnt < 8; text_cnt++) { push_data_to_gradio_component({ visible: false, label: "", __type__: 'update' - }, "plugin_arg_txt_"+text_cnt, "obj"); - document.getElementById("plugin_arg_txt_"+text_cnt).parentNode.parentNode.style.display = 'none'; + }, "plugin_arg_txt_" + text_cnt, "obj"); + document.getElementById("plugin_arg_txt_" + text_cnt).parentNode.parentNode.style.display = 'none'; } - for (dropdown_cnt = 0; dropdown_cnt < 8; dropdown_cnt++){ + for (dropdown_cnt = 0; dropdown_cnt < 8; dropdown_cnt++) { push_data_to_gradio_component({ visible: false, choices: [], label: "", __type__: 'update' - }, "plugin_arg_drop_"+dropdown_cnt, "obj"); - document.getElementById("plugin_arg_drop_"+dropdown_cnt).parentNode.style.display = 'none'; + }, "plugin_arg_drop_" + dropdown_cnt, "obj"); + document.getElementById("plugin_arg_drop_" + dropdown_cnt).parentNode.style.display = 'none'; } } -function close_current_pop_up_plugin(){ - // PLUGIN_ARG_MENU +function close_current_pop_up_plugin() { + // PLUGIN_ARG_MENU push_data_to_gradio_component({ visible: false, __type__: 'update' @@ -1233,15 +1350,13 @@ function close_current_pop_up_plugin(){ // 生成高级插件的选择菜单 plugin_init_info_lib = {} -function register_plugin_init(key, base64String){ +function register_plugin_init(key, base64String) { // console.log('x') const stringData = atob(base64String); let guiJsonData = JSON.parse(stringData); - if (key in plugin_init_info_lib) - { + if (key in plugin_init_info_lib) { } - else - { + else { plugin_init_info_lib[key] = {}; } plugin_init_info_lib[key].info = guiJsonData.Info; @@ -1251,28 +1366,26 @@ function register_plugin_init(key, base64String){ plugin_init_info_lib[key].enable_advanced_arg = guiJsonData.AdvancedArgs; plugin_init_info_lib[key].arg_reminder = guiJsonData.ArgsReminder; } -function register_advanced_plugin_init_code(key, code){ - if (key in plugin_init_info_lib) - { +function register_advanced_plugin_init_code(key, code) { + if (key in plugin_init_info_lib) { } - else - { + else { plugin_init_info_lib[key] = {}; } plugin_init_info_lib[key].secondary_menu_code = code; } -function run_advanced_plugin_launch_code(key){ +function run_advanced_plugin_launch_code(key) { // convert js code string to function generate_menu(plugin_init_info_lib[key].secondary_menu_code, key); } -function on_flex_button_click(key){ - if (plugin_init_info_lib.hasOwnProperty(key) && plugin_init_info_lib[key].hasOwnProperty('secondary_menu_code')){ +function on_flex_button_click(key) { + if (plugin_init_info_lib.hasOwnProperty(key) && plugin_init_info_lib[key].hasOwnProperty('secondary_menu_code')) { run_advanced_plugin_launch_code(key); - }else{ + } else { document.getElementById("old_callback_btn_for_plugin_exe").click(); } } -async function run_dropdown_shift(dropdown){ +async function run_dropdown_shift(dropdown) { let key = dropdown; push_data_to_gradio_component({ value: key, @@ -1281,7 +1394,7 @@ async function run_dropdown_shift(dropdown){ __type__: 'update' }, "elem_switchy_bt", "obj"); - if (plugin_init_info_lib[key].enable_advanced_arg){ + if (plugin_init_info_lib[key].enable_advanced_arg) { push_data_to_gradio_component({ visible: true, label: plugin_init_info_lib[key].label, @@ -1303,9 +1416,9 @@ async function duplicate_in_new_window() { window.open(url, '_blank'); } -async function run_classic_plugin_via_id(plugin_elem_id){ - for (key in plugin_init_info_lib){ - if (plugin_init_info_lib[key].elem_id == plugin_elem_id){ +async function run_classic_plugin_via_id(plugin_elem_id) { + for (key in plugin_init_info_lib) { + if (plugin_init_info_lib[key].elem_id == plugin_elem_id) { // 获取按钮名称 let current_btn_name = await get_data_from_gradio_component(plugin_elem_id); // 执行 @@ -1326,7 +1439,7 @@ async function call_plugin_via_name(current_btn_name) { hide_all_elem(); // 为了与旧插件兼容,生成菜单时,自动加载旧高级参数输入区的值 let advance_arg_input_legacy = await get_data_from_gradio_component('advance_arg_input_legacy'); - if (advance_arg_input_legacy.length != 0){ + if (advance_arg_input_legacy.length != 0) { gui_args["advanced_arg"] = {}; gui_args["advanced_arg"].user_confirmed_value = advance_arg_input_legacy; } @@ -1353,7 +1466,7 @@ async function multiplex_function_begin(multiplex_sel) { // do not delete `REPLACE_EXTENDED_MULTIPLEX_FUNCTIONS_HERE`! It will be read and replaced by Python code. // REPLACE_EXTENDED_MULTIPLEX_FUNCTIONS_HERE } -async function run_multiplex_shift(multiplex_sel){ +async function run_multiplex_shift(multiplex_sel) { let key = multiplex_sel; if (multiplex_sel === "常规对话") { key = "提交"; diff --git a/themes/gui_floating_menu.py b/themes/gui_floating_menu.py index 90947c5d..614d9d97 100644 --- a/themes/gui_floating_menu.py +++ b/themes/gui_floating_menu.py @@ -1,7 +1,7 @@ import gradio as gr def define_gui_floating_menu(customize_btns, functional, predefined_btns, cookies, web_cookie_cache): - with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_input_secondary: + with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top", elem_id="f_area_input_secondary") as area_input_secondary: with gr.Accordion("浮动输入区", open=True, elem_id="input-panel2"): with gr.Row() as row: row.style(equal_height=True) @@ -17,7 +17,7 @@ def define_gui_floating_menu(customize_btns, functional, predefined_btns, cookie clearBtn2 = gr.Button("清除", elem_id="elem_clear2", variant="secondary", visible=False); clearBtn2.style(size="sm") - with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_customize: + with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top", elem_id="f_area_customize") as area_customize: with gr.Accordion("自定义菜单", open=True, elem_id="edit-panel"): with gr.Row() as row: with gr.Column(scale=10): diff --git a/themes/init.js b/themes/init.js index 9ea8dd5a..179223de 100644 --- a/themes/init.js +++ b/themes/init.js @@ -3,6 +3,8 @@ async function GptAcademicJavaScriptInit(dark, prompt, live2d, layout, tts) { audio_fn_init(); minor_ui_adjustment(); ButtonWithDropdown_init(); + update_conversation_metadata(); + window.addEventListener("gptac_restore_chat_from_local_storage", restore_chat_from_local_storage); // 加载欢迎页面 const welcomeMessage = new WelcomeMessage(); diff --git a/themes/theme.py b/themes/theme.py index 28195774..96c3eed6 100644 --- a/themes/theme.py +++ b/themes/theme.py @@ -92,15 +92,6 @@ js_code_for_persistent_cookie_init = """(web_cookie_cache, cookie) => { } """ -# 详见 themes/common.js -js_code_reset = """ -(a,b,c)=>{ - let stopButton = document.getElementById("elem_stop"); - stopButton.click(); - return reset_conversation(a,b); -} -""" - js_code_clear = """ (a,b)=>{ diff --git a/themes/welcome.js b/themes/welcome.js index 8296b1f5..a6378e5a 100644 --- a/themes/welcome.js +++ b/themes/welcome.js @@ -84,7 +84,7 @@ class WelcomeMessage { this.max_welcome_card_num = 6; this.card_array = []; this.static_welcome_message_previous = []; - this.reflesh_time_interval = 15*1000; + this.reflesh_time_interval = 15 * 1000; const reflesh_render_status = () => { @@ -105,7 +105,7 @@ class WelcomeMessage { async startRefleshCards() { await new Promise(r => setTimeout(r, this.reflesh_time_interval)); await this.reflesh_cards(); - if (this.visible){ + if (this.visible) { setTimeout(() => { this.startRefleshCards.call(this); }, 1); @@ -113,7 +113,7 @@ class WelcomeMessage { } async reflesh_cards() { - if (!this.visible){ + if (!this.visible) { return; } @@ -173,18 +173,18 @@ class WelcomeMessage { } shuffle(array) { - var currentIndex = array.length, randomIndex; + var currentIndex = array.length, randomIndex; // While there remain elements to shuffle... while (currentIndex != 0) { - // Pick a remaining element... - randomIndex = Math.floor(Math.random() * currentIndex); - currentIndex--; + // Pick a remaining element... + randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex--; - // And swap it with the current element. - [array[currentIndex], array[randomIndex]] = [ - array[randomIndex], array[currentIndex]]; + // And swap it with the current element. + [array[currentIndex], array[randomIndex]] = [ + array[randomIndex], array[currentIndex]]; } return array; @@ -193,7 +193,7 @@ class WelcomeMessage { async update() { // console.log('update') var page_width = document.documentElement.clientWidth; - const width_to_hide_welcome = 1200; + const width_to_hide_welcome = 1000; if (!await this.isChatbotEmpty() || page_width < width_to_hide_welcome) { if (this.visible) { this.removeWelcome(); @@ -203,7 +203,7 @@ class WelcomeMessage { } return; } - if (this.visible){ + if (this.visible) { return; } // console.log("welcome"); @@ -220,28 +220,28 @@ class WelcomeMessage { const title = document.createElement('div'); title.classList.add('welcome-card-title'); - // 创建图标 - const svg = document.createElement('img'); - svg.classList.add('welcome-svg'); - svg.src = message.svg; - svg.style.height = '30px'; - title.appendChild(svg); + // 创建图标 + const svg = document.createElement('img'); + svg.classList.add('welcome-svg'); + svg.src = message.svg; + svg.style.height = '30px'; + title.appendChild(svg); - // 创建标题 - const text = document.createElement('a'); - text.textContent = message.title; - text.classList.add('welcome-title-text'); - text.href = message.url; - text.target = "_blank"; - title.appendChild(text) + // 创建标题 + const text = document.createElement('a'); + text.textContent = message.title; + text.classList.add('welcome-title-text'); + text.href = message.url; + text.target = "_blank"; + title.appendChild(text) // 创建内容 const content = document.createElement('div'); content.classList.add('welcome-content'); - const content_c = document.createElement('div'); - content_c.classList.add('welcome-content-c'); - content_c.textContent = message.content; - content.appendChild(content_c); + const content_c = document.createElement('div'); + content_c.classList.add('welcome-content-c'); + content_c.textContent = message.content; + content.appendChild(content_c); // 将标题和内容添加到卡片 div 中 card.appendChild(title); @@ -307,28 +307,28 @@ class WelcomeMessage { class PageFocusHandler { constructor() { - this.hasReturned = false; - this.focusCallbacks = []; + this.hasReturned = false; + this.focusCallbacks = []; - // Bind the focus and blur event handlers - window.addEventListener('visibilitychange', this.handleFocus.bind(this)); + // Bind the focus and blur event handlers + window.addEventListener('visibilitychange', this.handleFocus.bind(this)); } // Method to handle the focus event handleFocus() { - if (this.hasReturned) { - this.focusCallbacks.forEach(callback => callback()); - } - this.hasReturned = true; + if (this.hasReturned) { + this.focusCallbacks.forEach(callback => callback()); + } + this.hasReturned = true; } // Method to add a custom callback function addFocusCallback(callback) { - if (typeof callback === 'function') { - this.focusCallbacks.push(callback); - } else { - throw new Error('Callback must be a function'); - } + if (typeof callback === 'function') { + this.focusCallbacks.push(callback); + } else { + throw new Error('Callback must be a function'); + } } } diff --git a/toolbox.py b/toolbox.py index 060bf8dc..41c75178 100644 --- a/toolbox.py +++ b/toolbox.py @@ -8,6 +8,7 @@ import base64 import gradio import shutil import glob +import json import uuid from loguru import logger from functools import wraps @@ -92,8 +93,9 @@ def ArgsGeneralWrapper(f): """ def decorated(request: gradio.Request, cookies:dict, max_length:int, llm_model:str, txt:str, txt2:str, top_p:float, temperature:float, chatbot:list, - history:list, system_prompt:str, plugin_advanced_arg:dict, *args): + json_history:str, system_prompt:str, plugin_advanced_arg:dict, *args): txt_passon = txt + history = json.loads(json_history) if json_history else [] if txt == "" and txt2 != "": txt_passon = txt2 # 引入一个有cookie的chatbot if request.username is not None: @@ -148,10 +150,11 @@ def ArgsGeneralWrapper(f): return decorated -def update_ui(chatbot:ChatBotWithCookies, history, msg="正常", **kwargs): # 刷新界面 +def update_ui(chatbot:ChatBotWithCookies, history:list, msg:str="正常", **kwargs): # 刷新界面 """ 刷新用户界面 """ + assert isinstance(history, list), "history必须是一个list" assert isinstance( chatbot, ChatBotWithCookies ), "在传递chatbot的过程中不要将其丢弃。必要时, 可用clear将其清空, 然后用for+append循环重新赋值。" @@ -175,10 +178,11 @@ def update_ui(chatbot:ChatBotWithCookies, history, msg="正常", **kwargs): # else: chatbot_gr = chatbot - yield cookies, chatbot_gr, history, msg + json_history = json.dumps(history, ensure_ascii=False) + yield cookies, chatbot_gr, json_history, msg -def update_ui_lastest_msg(lastmsg:str, chatbot:ChatBotWithCookies, history:list, delay=1, msg="正常"): # 刷新界面 +def update_ui_lastest_msg(lastmsg:str, chatbot:ChatBotWithCookies, history:list, delay:float=1, msg:str="正常"): # 刷新界面 """ 刷新用户界面 """ From 48e53cba0524dd198de7c8f5e631352540cbf225 Mon Sep 17 00:00:00 2001 From: binary-husky Date: Sat, 7 Dec 2024 16:18:05 +0800 Subject: [PATCH 02/14] update gradio --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 7a3d9f86..95fe6295 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -https://public.agent-matrix.com/publish/gradio-3.32.10-py3-none-any.whl +https://public.agent-matrix.com/publish/gradio-3.32.12-py3-none-any.whl fastapi==0.110 gradio-client==0.8 pypdf2==2.12.1 From 94ccd77480f5dd1d58ec9be80e9073913fc5a4ef Mon Sep 17 00:00:00 2001 From: binary-husky Date: Sat, 7 Dec 2024 16:22:29 +0800 Subject: [PATCH 03/14] remove gen restore btn --- themes/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/common.js b/themes/common.js index 55727cc6..f12ab3ce 100644 --- a/themes/common.js +++ b/themes/common.js @@ -1058,7 +1058,7 @@ function reset_conversation(a, b) { setCookie("js_previous_chat_cookie", a, 1); b = btoa(unescape(encodeURIComponent(JSON.stringify(b)))); setCookie("js_previous_history_cookie", b, 1); - gen_restore_btn(); + // gen_restore_btn(); return [[], [], "已重置"]; } From 57d7dc33d376d1e0acc7a6e71128bd02df59fecd Mon Sep 17 00:00:00 2001 From: binary-husky Date: Sat, 7 Dec 2024 17:10:01 +0800 Subject: [PATCH 04/14] sync common.js --- themes/common.js | 16 +- themes/green.css | 1177 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 982 insertions(+), 211 deletions(-) diff --git a/themes/common.js b/themes/common.js index f12ab3ce..f525915e 100644 --- a/themes/common.js +++ b/themes/common.js @@ -1041,6 +1041,20 @@ function restore_chat_from_local_storage(event) { push_data_to_gradio_component(conversation.conversation, "gpt-chatbot", "obj"); push_data_to_gradio_component(conversation.history, "history-ng", "obj"); console.log("restore_chat_from_local_storage", conversation); + + // Create a conversation UUID and timestamp + const conversationId = conversation.id; + const timestamp = conversation.timestamp; + const conversationData = { + id: conversationId, + timestamp: timestamp + }; + // Save to cookie + setCookie("conversation_metadata", JSON.stringify(conversationData), 2); + // read from cookie + let conversation_metadata = getCookie("conversation_metadata"); + console.log("conversation_metadata", conversation_metadata); + } @@ -1058,7 +1072,7 @@ function reset_conversation(a, b) { setCookie("js_previous_chat_cookie", a, 1); b = btoa(unescape(encodeURIComponent(JSON.stringify(b)))); setCookie("js_previous_history_cookie", b, 1); - // gen_restore_btn(); + gen_restore_btn(); return [[], [], "已重置"]; } diff --git a/themes/green.css b/themes/green.css index 1235b800..d920372f 100644 --- a/themes/green.css +++ b/themes/green.css @@ -8,31 +8,39 @@ --message-bot-background-color-light: #FFFFFF; --message-bot-background-color-dark: #2C2C2C; } + mspace { display: block; } + @media only screen and (max-width: 767px) { - #column_1 { - display: none !important; - } + #column_1 { + display: none !important; + } } + @keyframes highlight { - 0%, 100% { - border: 2px solid transparent; - } - 50% { - border-color: yellow; - } + + 0%, + 100% { + border: 2px solid transparent; + } + + 50% { + border-color: yellow; + } } + .normal_mut_select .svelte-1gfkn6j { float: left; width: auto; line-height: 260% !important; } + #highlight_update { - animation-name: highlight; - animation-duration: 0.75s; - animation-iteration-count: 3; + animation-name: highlight; + animation-duration: 0.75s; + animation-iteration-count: 3; } .table-wrap.svelte-13hsdno.svelte-13hsdno.svelte-13hsdno { @@ -47,6 +55,7 @@ mspace { width: 100%; margin-bottom: 30% !important; } + #hide_examples { z-index: 0; } @@ -56,16 +65,19 @@ mspace { display: flex; bottom: 0; left: 0; - z-index: 1; /* 设置更高的 z-index 值 */ + z-index: 1; + /* 设置更高的 z-index 值 */ margin-bottom: -4px !important; align-self: flex-end; } + #chat_box { display: flex; flex-direction: column; overflow-y: visible !important; z-index: 3; - flex-grow: 1; /* 自动填充剩余空间 */ + flex-grow: 1; + /* 自动填充剩余空间 */ position: absolute; bottom: 0; left: 0; @@ -73,36 +85,41 @@ mspace { margin-bottom: 30px !important; border: 1px solid var(--border-color-primary); } + .toast-body { z-index: 5 !important; } -.chat_input { -} +.chat_input {} + .sm_btn { position: relative; bottom: 5px; height: 10%; - border-radius: 20px!important; - min-width: min(10%,100%) !important; + border-radius: 20px !important; + min-width: min(10%, 100%) !important; overflow: hidden; } + .sm_select { position: relative !important; z-index: 5 !important; bottom: 5px; - min-width: min(20%,100%) !important; - border-radius: 20px!important; + min-width: min(20%, 100%) !important; + border-radius: 20px !important; } + .sm_checkbox { position: relative !important; z-index: 5 !important; bottom: 5px; padding: 0 !important; } + .sm_select .wrap-inner.svelte-aqlk7e.svelte-aqlk7e.svelte-aqlk7e { padding: 0 !important; } + .sm_select .block.svelte-mppz8v { width: 10% !important; } @@ -115,7 +132,7 @@ button.sm { .insert_block { position: relative; bottom: 2px; - min-width: min(55px,100%) !important; + min-width: min(55px, 100%) !important; } .submit_btn { @@ -125,13 +142,15 @@ button.sm { bottom: 0; right: 10px; margin-bottom: 10px !important; - min-width: min(50px,100%) !important; + min-width: min(50px, 100%) !important; } textarea { resize: none; - height: 100%; /* 填充父元素的高度 */ + height: 100%; + /* 填充父元素的高度 */ } + /* #main_chatbot { height: 75vh !important; max-height: 75vh !important; @@ -141,7 +160,7 @@ textarea { backface-visibility: hidden !important; will-change: transform !important; } */ -#prompt_result{ +#prompt_result { height: 60vh !important; max-height: 60vh !important; } @@ -154,6 +173,7 @@ textarea { margin-top: 6px; white-space: nowrap; } + #description { text-align: center; margin: 32px 0 4px 0; @@ -165,36 +185,47 @@ footer { margin-top: .2em !important; font-size: 85%; } + #footer { text-align: center; } + #footer div { display: inline-block; } -#footer .versions{ + +#footer .versions { font-size: 85%; opacity: 0.60; } + /* user_info */ #float_display { position: absolute; max-height: 30px; } + /* user_info */ #user_info { white-space: nowrap; - position: absolute; left: 8em; top: .2em; + position: absolute; + left: 8em; + top: .2em; z-index: var(--layer-2); box-shadow: var(--block-shadow); - border: none; border-radius: var(--block-label-radius); + border: none; + border-radius: var(--block-label-radius); background: var(--color-accent); padding: var(--block-label-padding); - font-size: var(--block-label-text-size); line-height: var(--line-sm); - width: auto; min-height: 30px !important; + font-size: var(--block-label-text-size); + line-height: var(--line-sm); + width: auto; + min-height: 30px !important; opacity: 1; transition: opacity 0.3s ease-in-out; } + textarea.svelte-1pie7s6 { background: #f1f1f1 !important; width: 100% !important; @@ -209,36 +240,43 @@ textarea.svelte-1pie7s6 { background: #393939 !important; border: var(--input-border-width) solid var(--input-border-color) !important; } + /* .dark input[type="range"] { background: #393939 !important; } */ #user_info .wrap { opacity: 0; } + #user_info p { color: white; font-weight: var(--block-label-text-weight); } + #user_info.hideK { opacity: 0; transition: opacity 1s ease-in-out; } -[class *= "message"] { + +[class *="message"] { gap: 7px !important; border-radius: var(--radius-xl) !important } + /* debug_mes */ #debug_mes { min-height: 2em; align-items: flex-end; justify-content: flex-end; } + #debug_mes p { font-size: .85em; font-family: ui-monospace, "SF Mono", "SFMono-Regular", "Menlo", "Consolas", "Liberation Mono", "Microsoft Yahei UI", "Microsoft Yahei", monospace; /* Windows下中文的monospace会fallback为新宋体,实在太丑,这里折中使用微软雅黑 */ color: #000000; } + .dark #debug_mes p { color: #ee65ed; } @@ -246,6 +284,7 @@ textarea.svelte-1pie7s6 { #debug_mes { transition: all 0.6s; } + #gpt-chatbot { transition: height 0.3s ease; } @@ -274,36 +313,44 @@ textarea.svelte-1pie7s6 { font-weight: 600 !important; font-size: 24px !important; } + .gradio-container-3-32-2 h3 { font-weight: 500 !important; font-size: 20px !important; } + .gradio-container-3-32-2 h4 { font-weight: 400 !important; font-size: 16px !important; } + .gradio-container-3-32-2 h5 { font-weight: 300 !important; font-size: 14px !important; } + .gradio-container-3-32-2 h6 { font-weight: 200 !important; font-size: 12px !important; } -#usage_display p, #usage_display span { +#usage_display p, +#usage_display span { margin: 0; font-size: .85em; color: var(--body-text-color-subdued); } + .progress-bar { - background-color: var(--input-background-fill);; + background-color: var(--input-background-fill); + ; margin: .5em 0 !important; height: 20px; border-radius: 10px; overflow: hidden; } + .progress { background-color: var(--block-title-background-fill); height: 100%; @@ -311,6 +358,7 @@ textarea.svelte-1pie7s6 { text-align: right; transition: width 0.5s ease-in-out; } + .progress-text { /* color: white; */ color: var(--color-accent) !important; @@ -328,9 +376,11 @@ textarea.svelte-1pie7s6 { width: 48px; border-radius: 12px; } + .apSwitch input { display: none !important; } + .apSlider { background-color: var(--neutral-200); bottom: 0; @@ -343,6 +393,7 @@ textarea.svelte-1pie7s6 { font-size: 18px; border-radius: 7px; } + .apSlider::before { bottom: -1.5px; left: 1px; @@ -350,13 +401,15 @@ textarea.svelte-1pie7s6 { transition: .4s; content: "🌞"; } + hr.append-display { margin: 8px 0; border: none; height: 1px; border-top-width: 0; - background-image: linear-gradient(to right, rgba(50,50,50, 0.1), rgba(150, 150, 150, 0.8), rgba(50,50,50, 0.1)); + background-image: linear-gradient(to right, rgba(50, 50, 50, 0.1), rgba(150, 150, 150, 0.8), rgba(50, 50, 50, 0.1)); } + .source-a { font-size: 0.8em; max-width: 100%; @@ -369,6 +422,7 @@ hr.append-display { border-radius: 1.5rem; padding: 0.2em; } + .source-a a { display: inline-block; background-color: #aaaaaa50; @@ -384,16 +438,19 @@ hr.append-display { flex: 1; transition: flex 0.5s; } + .source-a a:hover { background-color: #aaaaaa20; flex: 2; } -input:checked + .apSlider { + +input:checked+.apSlider { background-color: var(--primary-600); } -input:checked + .apSlider::before { + +input:checked+.apSlider::before { transform: translateX(23px); - content:"🌚"; + content: "🌚"; } /* Override Slider Styles (for webkit browsers like Safari and Chrome) @@ -405,10 +462,11 @@ input[type="range"] { height: 4px; background: var(--input-background-fill); border-radius: 5px; - background-image: linear-gradient(var(--primary-500),var(--primary-500)); + background-image: linear-gradient(var(--primary-500), var(--primary-500)); background-size: 0% 100%; background-repeat: no-repeat; } + input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; height: 20px; @@ -420,9 +478,11 @@ input[type="range"]::-webkit-slider-thumb { box-shadow: var(--input-shadow); transition: background-color .1s ease; } + input[type="range"]::-webkit-slider-thumb:hover { background: var(--neutral-50); } + input[type="range"]::-webkit-slider-runnable-track { -webkit-appearance: none; box-shadow: none; @@ -430,9 +490,11 @@ input[type="range"]::-webkit-slider-runnable-track { background: transparent; } -.submit_btn, #cancel_btn { +.submit_btn, +#cancel_btn { height: 42px !important; } + .submit_btn::before { content: url("data:image/svg+xml, %3Csvg width='21px' height='20px' viewBox='0 0 21 20' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E %3Cg id='page' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E %3Cg id='send' transform='translate(0.435849, 0.088463)' fill='%23FFFFFF' fill-rule='nonzero'%3E %3Cpath d='M0.579148261,0.0428666046 C0.301105539,-0.0961547561 -0.036517765,0.122307382 0.0032026237,0.420210298 L1.4927172,18.1553639 C1.5125774,18.4334066 1.79062012,18.5922882 2.04880264,18.4929872 L8.24518329,15.8913017 L11.6412765,19.7441794 C11.8597387,19.9825018 12.2370824,19.8832008 12.3165231,19.5852979 L13.9450591,13.4882182 L19.7839562,11.0255541 C20.0619989,10.8865327 20.0818591,10.4694687 19.7839562,10.3105871 L0.579148261,0.0428666046 Z M11.6138902,17.0883151 L9.85385903,14.7195502 L0.718169621,0.618812241 L12.69945,12.9346347 L11.6138902,17.0883151 Z' id='shape'%3E%3C/path%3E %3C/g%3E %3C/g%3E %3C/svg%3E"); height: 21px; @@ -442,8 +504,10 @@ input[type="range"]::-webkit-slider-runnable-track { content: url("data:image/svg+xml,%3Csvg width='21px' height='21px' viewBox='0 0 21 21' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E %3Cg id='pg' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E %3Cpath d='M10.2072007,20.088463 C11.5727865,20.088463 12.8594566,19.8259823 14.067211,19.3010209 C15.2749653,18.7760595 16.3386126,18.0538087 17.2581528,17.1342685 C18.177693,16.2147282 18.8982283,15.1527965 19.4197586,13.9484733 C19.9412889,12.7441501 20.202054,11.4557644 20.202054,10.0833163 C20.202054,8.71773046 19.9395733,7.43106036 19.4146119,6.22330603 C18.8896505,5.01555169 18.1673997,3.95018885 17.2478595,3.0272175 C16.3283192,2.10424615 15.2646719,1.3837109 14.0569176,0.865611739 C12.8491633,0.34751258 11.5624932,0.088463 10.1969073,0.088463 C8.83132146,0.088463 7.54636692,0.34751258 6.34204371,0.865611739 C5.1377205,1.3837109 4.07407321,2.10424615 3.15110186,3.0272175 C2.22813051,3.95018885 1.5058797,5.01555169 0.984349419,6.22330603 C0.46281914,7.43106036 0.202054,8.71773046 0.202054,10.0833163 C0.202054,11.4557644 0.4645347,12.7441501 0.9894961,13.9484733 C1.5144575,15.1527965 2.23670831,16.2147282 3.15624854,17.1342685 C4.07578877,18.0538087 5.1377205,18.7760595 6.34204371,19.3010209 C7.54636692,19.8259823 8.83475258,20.088463 10.2072007,20.088463 Z M10.2072007,18.2562448 C9.07493099,18.2562448 8.01471483,18.0452309 7.0265522,17.6232031 C6.03838956,17.2011753 5.17031614,16.6161693 4.42233192,15.8681851 C3.6743477,15.1202009 3.09105726,14.2521274 2.67246059,13.2639648 C2.25386392,12.2758022 2.04456558,11.215586 2.04456558,10.0833163 C2.04456558,8.95104663 2.25386392,7.89083047 2.67246059,6.90266784 C3.09105726,5.9145052 3.6743477,5.04643178 4.42233192,4.29844756 C5.17031614,3.55046334 6.036674,2.9671729 7.02140552,2.54857623 C8.00613703,2.12997956 9.06463763,1.92068122 10.1969073,1.92068122 C11.329177,1.92068122 12.3911087,2.12997956 13.3827025,2.54857623 C14.3742962,2.9671729 15.2440852,3.55046334 15.9920694,4.29844756 C16.7400537,5.04643178 17.3233441,5.9145052 17.7419408,6.90266784 C18.1605374,7.89083047 18.3698358,8.95104663 18.3698358,10.0833163 C18.3698358,11.215586 18.1605374,12.2758022 17.7419408,13.2639648 C17.3233441,14.2521274 16.7400537,15.1202009 15.9920694,15.8681851 C15.2440852,16.6161693 14.3760118,17.2011753 13.3878492,17.6232031 C12.3996865,18.0452309 11.3394704,18.2562448 10.2072007,18.2562448 Z M7.65444721,13.6242324 L12.7496608,13.6242324 C13.0584616,13.6242324 13.3003556,13.5384544 13.4753427,13.3668984 C13.6503299,13.1953424 13.7378234,12.9585951 13.7378234,12.6566565 L13.7378234,7.49968276 C13.7378234,7.19774418 13.6503299,6.96099688 13.4753427,6.78944087 C13.3003556,6.61788486 13.0584616,6.53210685 12.7496608,6.53210685 L7.65444721,6.53210685 C7.33878414,6.53210685 7.09345904,6.61788486 6.91847191,6.78944087 C6.74348478,6.96099688 6.65599121,7.19774418 6.65599121,7.49968276 L6.65599121,12.6566565 C6.65599121,12.9585951 6.74348478,13.1953424 6.91847191,13.3668984 C7.09345904,13.5384544 7.33878414,13.6242324 7.65444721,13.6242324 Z' id='shape' fill='%23FF3B30' fill-rule='nonzero'%3E%3C/path%3E %3C/g%3E %3C/svg%3E"); height: 21px; } + /* list */ -ol:not(.options), ul:not(.options) { +ol:not(.options), +ul:not(.options) { padding-inline-start: 2em !important; } @@ -453,6 +517,7 @@ ol:not(.options), ul:not(.options) { color: var(--chatbot-color-light) !important; box-shadow: 0 0 12px 4px rgba(0, 0, 0, 0.06); } + /* 暗色 */ .dark #gpt-chatbot { background-color: var(--block-background-fill) !important; @@ -460,10 +525,11 @@ ol:not(.options), ul:not(.options) { box-shadow: 0 0 12px 4px rgba(0, 0, 0, 0.2); } -#gpt-panel > div { +#gpt-panel>div { box-shadow: 0 0 12px 4px rgba(0, 0, 0, 0.06); } -.dark #gpt-panel > div { + +.dark #gpt-panel>div { box-shadow: 0 0 12px 4px rgba(0, 0, 0, 0.2); } @@ -495,6 +561,7 @@ ol:not(.options), ul:not(.options) { #gpt-chatbot .wrap { overflow-x: hidden } + /* 对话气泡 */ .message { border-radius: var(--radius-xl) !important; @@ -505,23 +572,27 @@ ol:not(.options), ul:not(.options) { min-height: calc(var(--text-md)*var(--line-md) + 2*var(--spacing-xl)); min-width: calc(var(--text-md)*var(--line-md) + 2*var(--spacing-xl)); } -[data-testid = "bot"] { + +[data-testid="bot"] { max-width: 85%; border-bottom-left-radius: 0 !important; box-shadow: 2px 2px 0px 1px rgba(0, 0, 0, 0.06); background-color: var(--message-bot-background-color-light) !important; } -[data-testid = "user"] { + +[data-testid="user"] { max-width: 85%; width: auto !important; border-bottom-right-radius: 0 !important; box-shadow: 2px 2px 0px 1px rgba(0, 0, 0, 0.06); background-color: var(--message-user-background-color-light) !important; } -.dark [data-testid = "bot"] { + +.dark [data-testid="bot"] { background-color: var(--message-bot-background-color-dark) !important; } -.dark [data-testid = "user"] { + +.dark [data-testid="user"] { background-color: var(--message-user-background-color-dark) !important; } @@ -529,19 +600,28 @@ ol:not(.options), ul:not(.options) { margin-top: 0.6em !important; margin-bottom: 0.6em !important; } -.message p:first-child { margin-top: 0 !important; } -.message p:last-of-type { margin-bottom: 0 !important; } + +.message p:first-child { + margin-top: 0 !important; +} + +.message p:last-of-type { + margin-bottom: 0 !important; +} .message .md-message { display: block; padding: 0 !important; } + .message .raw-message { display: block; padding: 0 !important; white-space: pre-wrap; } -.raw-message.hideM, .md-message.hideM { + +.raw-message.hideM, +.md-message.hideM { display: none; } @@ -556,24 +636,30 @@ ol:not(.options), ul:not(.options) { cursor: pointer !important; transition: color .2s ease, background-color .2s ease; } + .chuanhu-btn:hover { background-color: rgba(167, 167, 167, 0.25) !important; color: unset !important; } + .chuanhu-btn:active { background-color: rgba(167, 167, 167, 0.5) !important; } + .chuanhu-btn:focus { outline: none; } + .copy-bot-btn { /* top: 18px; */ bottom: 0; } + .toggle-md-btn { /* top: 0; */ bottom: 20px; } + .copy-code-btn { position: relative; float: right; @@ -581,7 +667,7 @@ ol:not(.options), ul:not(.options) { cursor: pointer; } -.message-wrap>div img{ +.message-wrap>div img { border-radius: 10px !important; } @@ -589,22 +675,27 @@ ol:not(.options), ul:not(.options) { .wrap>.history-message { padding: 10px !important; } + .history-message { /* padding: 0 !important; */ opacity: 80%; display: flex; flex-direction: column; } + .history-message>.history-message { padding: 0 !important; } + .history-message>.message-wrap { padding: 0 !important; margin-bottom: 16px; } + .history-message>.message { margin-bottom: 16px; } + .wrap>.history-message::after { content: ""; display: block; @@ -614,6 +705,7 @@ ol:not(.options), ul:not(.options) { margin-top: -10px; clear: both; } + .wrap>.history-message>:last-child::after { content: "仅供查看"; display: block; @@ -628,16 +720,21 @@ table { border-collapse: collapse; empty-cells: show; } -td,th { + +td, +th { border: 1.2px solid var(--border-color-primary) !important; padding: 0.2em; } + thead { - background-color: rgba(175,184,193,0.2); + background-color: rgba(175, 184, 193, 0.2); } + thead th { padding: .5em .2em; } + /* 行内代码 */ .message :not(pre) code { display: inline; @@ -645,26 +742,30 @@ thead th { border-radius: 6px; margin: 0 2px 0 2px; padding: .2em .4em .1em .4em; - background-color: rgba(175,184,193,0.2); + background-color: rgba(175, 184, 193, 0.2); } + /* 代码块 */ .message pre code { display: block; overflow: auto; white-space: pre; - background-color: hsla(0, 0%, 7%, 70%)!important; + background-color: hsla(0, 0%, 7%, 70%) !important; border-radius: 10px; padding: 1.2em 1em 0em .5em; margin: 0.6em 2em 1em 0.2em; color: #FFF; box-shadow: 6px 6px 16px hsla(0, 0%, 0%, 0.2); } + .dark .message pre code { - background-color: hsla(0, 0%, 20%, 300%)!important; + background-color: hsla(0, 0%, 20%, 300%) !important; } + .message pre { padding: 0 !important; } + .message pre code div.highlight { background-color: unset !important; } @@ -674,160 +775,816 @@ button.copy-button { } /* 代码高亮样式 */ -.codehilite .hll { background-color: #6e7681 } -.codehilite .c { color: #8b949e; font-style: italic } /* Comment */ -.codehilite .err { color: #f85149 } /* Error */ -.codehilite .esc { color: #c9d1d9 } /* Escape */ -.codehilite .g { color: #c9d1d9 } /* Generic */ -.codehilite .k { color: #ff7b72 } /* Keyword */ -.codehilite .l { color: #a5d6ff } /* Literal */ -.codehilite .n { color: #c9d1d9 } /* Name */ -.codehilite .o { color: #ff7b72; font-weight: bold } /* Operator */ -.codehilite .x { color: #c9d1d9 } /* Other */ -.codehilite .p { color: #c9d1d9 } /* Punctuation */ -.codehilite .ch { color: #8b949e; font-style: italic } /* Comment.Hashbang */ -.codehilite .cm { color: #8b949e; font-style: italic } /* Comment.Multiline */ -.codehilite .cp { color: #8b949e; font-weight: bold; font-style: italic } /* Comment.Preproc */ -.codehilite .cpf { color: #8b949e; font-style: italic } /* Comment.PreprocFile */ -.codehilite .c1 { color: #8b949e; font-style: italic } /* Comment.Single */ -.codehilite .cs { color: #8b949e; font-weight: bold; font-style: italic } /* Comment.Special */ -.codehilite .gd { color: #ffa198; background-color: #490202 } /* Generic.Deleted */ -.codehilite .ge { color: #c9d1d9; font-style: italic } /* Generic.Emph */ -.codehilite .gr { color: #ffa198 } /* Generic.Error */ -.codehilite .gh { color: #79c0ff; font-weight: bold } /* Generic.Heading */ -.codehilite .gi { color: #56d364; background-color: #0f5323 } /* Generic.Inserted */ -.codehilite .go { color: #8b949e } /* Generic.Output */ -.codehilite .gp { color: #8b949e } /* Generic.Prompt */ -.codehilite .gs { color: #c9d1d9; font-weight: bold } /* Generic.Strong */ -.codehilite .gu { color: #79c0ff } /* Generic.Subheading */ -.codehilite .gt { color: #ff7b72 } /* Generic.Traceback */ -.codehilite .g-Underline { color: #c9d1d9; text-decoration: underline } /* Generic.Underline */ -.codehilite .kc { color: #79c0ff } /* Keyword.Constant */ -.codehilite .kd { color: #ff7b72 } /* Keyword.Declaration */ -.codehilite .kn { color: #ff7b72 } /* Keyword.Namespace */ -.codehilite .kp { color: #79c0ff } /* Keyword.Pseudo */ -.codehilite .kr { color: #ff7b72 } /* Keyword.Reserved */ -.codehilite .kt { color: #ff7b72 } /* Keyword.Type */ -.codehilite .ld { color: #79c0ff } /* Literal.Date */ -.codehilite .m { color: #a5d6ff } /* Literal.Number */ -.codehilite .s { color: #a5d6ff } /* Literal.String */ -.codehilite .na { color: #c9d1d9 } /* Name.Attribute */ -.codehilite .nb { color: #c9d1d9 } /* Name.Builtin */ -.codehilite .nc { color: #f0883e; font-weight: bold } /* Name.Class */ -.codehilite .no { color: #79c0ff; font-weight: bold } /* Name.Constant */ -.codehilite .nd { color: #d2a8ff; font-weight: bold } /* Name.Decorator */ -.codehilite .ni { color: #ffa657 } /* Name.Entity */ -.codehilite .ne { color: #f0883e; font-weight: bold } /* Name.Exception */ -.codehilite .nf { color: #d2a8ff; font-weight: bold } /* Name.Function */ -.codehilite .nl { color: #79c0ff; font-weight: bold } /* Name.Label */ -.codehilite .nn { color: #ff7b72 } /* Name.Namespace */ -.codehilite .nx { color: #c9d1d9 } /* Name.Other */ -.codehilite .py { color: #79c0ff } /* Name.Property */ -.codehilite .nt { color: #7ee787 } /* Name.Tag */ -.codehilite .nv { color: #79c0ff } /* Name.Variable */ -.codehilite .ow { color: #ff7b72; font-weight: bold } /* Operator.Word */ -.codehilite .pm { color: #c9d1d9 } /* Punctuation.Marker */ -.codehilite .w { color: #6e7681 } /* Text.Whitespace */ -.codehilite .mb { color: #a5d6ff } /* Literal.Number.Bin */ -.codehilite .mf { color: #a5d6ff } /* Literal.Number.Float */ -.codehilite .mh { color: #a5d6ff } /* Literal.Number.Hex */ -.codehilite .mi { color: #a5d6ff } /* Literal.Number.Integer */ -.codehilite .mo { color: #a5d6ff } /* Literal.Number.Oct */ -.codehilite .sa { color: #79c0ff } /* Literal.String.Affix */ -.codehilite .sb { color: #a5d6ff } /* Literal.String.Backtick */ -.codehilite .sc { color: #a5d6ff } /* Literal.String.Char */ -.codehilite .dl { color: #79c0ff } /* Literal.String.Delimiter */ -.codehilite .sd { color: #a5d6ff } /* Literal.String.Doc */ -.codehilite .s2 { color: #a5d6ff } /* Literal.String.Double */ -.codehilite .se { color: #79c0ff } /* Literal.String.Escape */ -.codehilite .sh { color: #79c0ff } /* Literal.String.Heredoc */ -.codehilite .si { color: #a5d6ff } /* Literal.String.Interpol */ -.codehilite .sx { color: #a5d6ff } /* Literal.String.Other */ -.codehilite .sr { color: #79c0ff } /* Literal.String.Regex */ -.codehilite .s1 { color: #a5d6ff } /* Literal.String.Single */ -.codehilite .ss { color: #a5d6ff } /* Literal.String.Symbol */ -.codehilite .bp { color: #c9d1d9 } /* Name.Builtin.Pseudo */ -.codehilite .fm { color: #d2a8ff; font-weight: bold } /* Name.Function.Magic */ -.codehilite .vc { color: #79c0ff } /* Name.Variable.Class */ -.codehilite .vg { color: #79c0ff } /* Name.Variable.Global */ -.codehilite .vi { color: #79c0ff } /* Name.Variable.Instance */ -.codehilite .vm { color: #79c0ff } /* Name.Variable.Magic */ -.codehilite .il { color: #a5d6ff } /* Literal.Number.Integer.Long */ +.codehilite .hll { + background-color: #6e7681 +} -.dark .codehilite .hll { background-color: #2C3B41 } -.dark .codehilite .c { color: #79d618; font-style: italic } /* Comment */ -.dark .codehilite .err { color: #FF5370 } /* Error */ -.dark .codehilite .esc { color: #89DDFF } /* Escape */ -.dark .codehilite .g { color: #EEFFFF } /* Generic */ -.dark .codehilite .k { color: #BB80B3 } /* Keyword */ -.dark .codehilite .l { color: #C3E88D } /* Literal */ -.dark .codehilite .n { color: #EEFFFF } /* Name */ -.dark .codehilite .o { color: #89DDFF } /* Operator */ -.dark .codehilite .p { color: #89DDFF } /* Punctuation */ -.dark .codehilite .ch { color: #79d618; font-style: italic } /* Comment.Hashbang */ -.dark .codehilite .cm { color: #79d618; font-style: italic } /* Comment.Multiline */ -.dark .codehilite .cp { color: #79d618; font-style: italic } /* Comment.Preproc */ -.dark .codehilite .cpf { color: #79d618; font-style: italic } /* Comment.PreprocFile */ -.dark .codehilite .c1 { color: #79d618; font-style: italic } /* Comment.Single */ -.dark .codehilite .cs { color: #79d618; font-style: italic } /* Comment.Special */ -.dark .codehilite .gd { color: #FF5370 } /* Generic.Deleted */ -.dark .codehilite .ge { color: #89DDFF } /* Generic.Emph */ -.dark .codehilite .gr { color: #FF5370 } /* Generic.Error */ -.dark .codehilite .gh { color: #C3E88D } /* Generic.Heading */ -.dark .codehilite .gi { color: #C3E88D } /* Generic.Inserted */ -.dark .codehilite .go { color: #79d618 } /* Generic.Output */ -.dark .codehilite .gp { color: #FFCB6B } /* Generic.Prompt */ -.dark .codehilite .gs { color: #FF5370 } /* Generic.Strong */ -.dark .codehilite .gu { color: #89DDFF } /* Generic.Subheading */ -.dark .codehilite .gt { color: #FF5370 } /* Generic.Traceback */ -.dark .codehilite .kc { color: #89DDFF } /* Keyword.Constant */ -.dark .codehilite .kd { color: #BB80B3 } /* Keyword.Declaration */ -.dark .codehilite .kn { color: #89DDFF; font-style: italic } /* Keyword.Namespace */ -.dark .codehilite .kp { color: #89DDFF } /* Keyword.Pseudo */ -.dark .codehilite .kr { color: #BB80B3 } /* Keyword.Reserved */ -.dark .codehilite .kt { color: #BB80B3 } /* Keyword.Type */ -.dark .codehilite .ld { color: #C3E88D } /* Literal.Date */ -.dark .codehilite .m { color: #F78C6C } /* Literal.Number */ -.dark .codehilite .s { color: #C3E88D } /* Literal.String */ -.dark .codehilite .na { color: #BB80B3 } /* Name.Attribute */ -.dark .codehilite .nb { color: #82AAFF } /* Name.Builtin */ -.dark .codehilite .nc { color: #FFCB6B } /* Name.Class */ -.dark .codehilite .no { color: #EEFFFF } /* Name.Constant */ -.dark .codehilite .nd { color: #82AAFF } /* Name.Decorator */ -.dark .codehilite .ni { color: #89DDFF } /* Name.Entity */ -.dark .codehilite .ne { color: #FFCB6B } /* Name.Exception */ -.dark .codehilite .nf { color: #82AAFF } /* Name.Function */ -.dark .codehilite .nl { color: #82AAFF } /* Name.Label */ -.dark .codehilite .nn { color: #FFCB6B } /* Name.Namespace */ -.dark .codehilite .nx { color: #EEFFFF } /* Name.Other */ -.dark .codehilite .py { color: #FFCB6B } /* Name.Property */ -.dark .codehilite .nt { color: #FF5370 } /* Name.Tag */ -.dark .codehilite .nv { color: #89DDFF } /* Name.Variable */ -.dark .codehilite .ow { color: #89DDFF; font-style: italic } /* Operator.Word */ -.dark .codehilite .pm { color: #89DDFF } /* Punctuation.Marker */ -.dark .codehilite .w { color: #EEFFFF } /* Text.Whitespace */ -.dark .codehilite .mb { color: #F78C6C } /* Literal.Number.Bin */ -.dark .codehilite .mf { color: #F78C6C } /* Literal.Number.Float */ -.dark .codehilite .mh { color: #F78C6C } /* Literal.Number.Hex */ -.dark .codehilite .mi { color: #F78C6C } /* Literal.Number.Integer */ -.dark .codehilite .mo { color: #F78C6C } /* Literal.Number.Oct */ -.dark .codehilite .sa { color: #BB80B3 } /* Literal.String.Affix */ -.dark .codehilite .sb { color: #C3E88D } /* Literal.String.Backtick */ -.dark .codehilite .sc { color: #C3E88D } /* Literal.String.Char */ -.dark .codehilite .dl { color: #EEFFFF } /* Literal.String.Delimiter */ -.dark .codehilite .sd { color: #79d618; font-style: italic } /* Literal.String.Doc */ -.dark .codehilite .s2 { color: #C3E88D } /* Literal.String.Double */ -.dark .codehilite .se { color: #EEFFFF } /* Literal.String.Escape */ -.dark .codehilite .sh { color: #C3E88D } /* Literal.String.Heredoc */ -.dark .codehilite .si { color: #89DDFF } /* Literal.String.Interpol */ -.dark .codehilite .sx { color: #C3E88D } /* Literal.String.Other */ -.dark .codehilite .sr { color: #89DDFF } /* Literal.String.Regex */ -.dark .codehilite .s1 { color: #C3E88D } /* Literal.String.Single */ -.dark .codehilite .ss { color: #89DDFF } /* Literal.String.Symbol */ -.dark .codehilite .bp { color: #89DDFF } /* Name.Builtin.Pseudo */ -.dark .codehilite .fm { color: #82AAFF } /* Name.Function.Magic */ -.dark .codehilite .vc { color: #89DDFF } /* Name.Variable.Class */ -.dark .codehilite .vg { color: #89DDFF } /* Name.Variable.Global */ -.dark .codehilite .vi { color: #89DDFF } /* Name.Variable.Instance */ -.dark .codehilite .vm { color: #82AAFF } /* Name.Variable.Magic */ -.dark .codehilite .il { color: #F78C6C } /* Literal.Number.Integer.Long */ +.codehilite .c { + color: #8b949e; + font-style: italic +} + +/* Comment */ +.codehilite .err { + color: #f85149 +} + +/* Error */ +.codehilite .esc { + color: #c9d1d9 +} + +/* Escape */ +.codehilite .g { + color: #c9d1d9 +} + +/* Generic */ +.codehilite .k { + color: #ff7b72 +} + +/* Keyword */ +.codehilite .l { + color: #a5d6ff +} + +/* Literal */ +.codehilite .n { + color: #c9d1d9 +} + +/* Name */ +.codehilite .o { + color: #ff7b72; + font-weight: bold +} + +/* Operator */ +.codehilite .x { + color: #c9d1d9 +} + +/* Other */ +.codehilite .p { + color: #c9d1d9 +} + +/* Punctuation */ +.codehilite .ch { + color: #8b949e; + font-style: italic +} + +/* Comment.Hashbang */ +.codehilite .cm { + color: #8b949e; + font-style: italic +} + +/* Comment.Multiline */ +.codehilite .cp { + color: #8b949e; + font-weight: bold; + font-style: italic +} + +/* Comment.Preproc */ +.codehilite .cpf { + color: #8b949e; + font-style: italic +} + +/* Comment.PreprocFile */ +.codehilite .c1 { + color: #8b949e; + font-style: italic +} + +/* Comment.Single */ +.codehilite .cs { + color: #8b949e; + font-weight: bold; + font-style: italic +} + +/* Comment.Special */ +.codehilite .gd { + color: #ffa198; + background-color: #490202 +} + +/* Generic.Deleted */ +.codehilite .ge { + color: #c9d1d9; + font-style: italic +} + +/* Generic.Emph */ +.codehilite .gr { + color: #ffa198 +} + +/* Generic.Error */ +.codehilite .gh { + color: #79c0ff; + font-weight: bold +} + +/* Generic.Heading */ +.codehilite .gi { + color: #56d364; + background-color: #0f5323 +} + +/* Generic.Inserted */ +.codehilite .go { + color: #8b949e +} + +/* Generic.Output */ +.codehilite .gp { + color: #8b949e +} + +/* Generic.Prompt */ +.codehilite .gs { + color: #c9d1d9; + font-weight: bold +} + +/* Generic.Strong */ +.codehilite .gu { + color: #79c0ff +} + +/* Generic.Subheading */ +.codehilite .gt { + color: #ff7b72 +} + +/* Generic.Traceback */ +.codehilite .g-Underline { + color: #c9d1d9; + text-decoration: underline +} + +/* Generic.Underline */ +.codehilite .kc { + color: #79c0ff +} + +/* Keyword.Constant */ +.codehilite .kd { + color: #ff7b72 +} + +/* Keyword.Declaration */ +.codehilite .kn { + color: #ff7b72 +} + +/* Keyword.Namespace */ +.codehilite .kp { + color: #79c0ff +} + +/* Keyword.Pseudo */ +.codehilite .kr { + color: #ff7b72 +} + +/* Keyword.Reserved */ +.codehilite .kt { + color: #ff7b72 +} + +/* Keyword.Type */ +.codehilite .ld { + color: #79c0ff +} + +/* Literal.Date */ +.codehilite .m { + color: #a5d6ff +} + +/* Literal.Number */ +.codehilite .s { + color: #a5d6ff +} + +/* Literal.String */ +.codehilite .na { + color: #c9d1d9 +} + +/* Name.Attribute */ +.codehilite .nb { + color: #c9d1d9 +} + +/* Name.Builtin */ +.codehilite .nc { + color: #f0883e; + font-weight: bold +} + +/* Name.Class */ +.codehilite .no { + color: #79c0ff; + font-weight: bold +} + +/* Name.Constant */ +.codehilite .nd { + color: #d2a8ff; + font-weight: bold +} + +/* Name.Decorator */ +.codehilite .ni { + color: #ffa657 +} + +/* Name.Entity */ +.codehilite .ne { + color: #f0883e; + font-weight: bold +} + +/* Name.Exception */ +.codehilite .nf { + color: #d2a8ff; + font-weight: bold +} + +/* Name.Function */ +.codehilite .nl { + color: #79c0ff; + font-weight: bold +} + +/* Name.Label */ +.codehilite .nn { + color: #ff7b72 +} + +/* Name.Namespace */ +.codehilite .nx { + color: #c9d1d9 +} + +/* Name.Other */ +.codehilite .py { + color: #79c0ff +} + +/* Name.Property */ +.codehilite .nt { + color: #7ee787 +} + +/* Name.Tag */ +.codehilite .nv { + color: #79c0ff +} + +/* Name.Variable */ +.codehilite .ow { + color: #ff7b72; + font-weight: bold +} + +/* Operator.Word */ +.codehilite .pm { + color: #c9d1d9 +} + +/* Punctuation.Marker */ +.codehilite .w { + color: #6e7681 +} + +/* Text.Whitespace */ +.codehilite .mb { + color: #a5d6ff +} + +/* Literal.Number.Bin */ +.codehilite .mf { + color: #a5d6ff +} + +/* Literal.Number.Float */ +.codehilite .mh { + color: #a5d6ff +} + +/* Literal.Number.Hex */ +.codehilite .mi { + color: #a5d6ff +} + +/* Literal.Number.Integer */ +.codehilite .mo { + color: #a5d6ff +} + +/* Literal.Number.Oct */ +.codehilite .sa { + color: #79c0ff +} + +/* Literal.String.Affix */ +.codehilite .sb { + color: #a5d6ff +} + +/* Literal.String.Backtick */ +.codehilite .sc { + color: #a5d6ff +} + +/* Literal.String.Char */ +.codehilite .dl { + color: #79c0ff +} + +/* Literal.String.Delimiter */ +.codehilite .sd { + color: #a5d6ff +} + +/* Literal.String.Doc */ +.codehilite .s2 { + color: #a5d6ff +} + +/* Literal.String.Double */ +.codehilite .se { + color: #79c0ff +} + +/* Literal.String.Escape */ +.codehilite .sh { + color: #79c0ff +} + +/* Literal.String.Heredoc */ +.codehilite .si { + color: #a5d6ff +} + +/* Literal.String.Interpol */ +.codehilite .sx { + color: #a5d6ff +} + +/* Literal.String.Other */ +.codehilite .sr { + color: #79c0ff +} + +/* Literal.String.Regex */ +.codehilite .s1 { + color: #a5d6ff +} + +/* Literal.String.Single */ +.codehilite .ss { + color: #a5d6ff +} + +/* Literal.String.Symbol */ +.codehilite .bp { + color: #c9d1d9 +} + +/* Name.Builtin.Pseudo */ +.codehilite .fm { + color: #d2a8ff; + font-weight: bold +} + +/* Name.Function.Magic */ +.codehilite .vc { + color: #79c0ff +} + +/* Name.Variable.Class */ +.codehilite .vg { + color: #79c0ff +} + +/* Name.Variable.Global */ +.codehilite .vi { + color: #79c0ff +} + +/* Name.Variable.Instance */ +.codehilite .vm { + color: #79c0ff +} + +/* Name.Variable.Magic */ +.codehilite .il { + color: #a5d6ff +} + +/* Literal.Number.Integer.Long */ + +.dark .codehilite .hll { + background-color: #2C3B41 +} + +.dark .codehilite .c { + color: #79d618; + font-style: italic +} + +/* Comment */ +.dark .codehilite .err { + color: #FF5370 +} + +/* Error */ +.dark .codehilite .esc { + color: #89DDFF +} + +/* Escape */ +.dark .codehilite .g { + color: #EEFFFF +} + +/* Generic */ +.dark .codehilite .k { + color: #BB80B3 +} + +/* Keyword */ +.dark .codehilite .l { + color: #C3E88D +} + +/* Literal */ +.dark .codehilite .n { + color: #EEFFFF +} + +/* Name */ +.dark .codehilite .o { + color: #89DDFF +} + +/* Operator */ +.dark .codehilite .p { + color: #89DDFF +} + +/* Punctuation */ +.dark .codehilite .ch { + color: #79d618; + font-style: italic +} + +/* Comment.Hashbang */ +.dark .codehilite .cm { + color: #79d618; + font-style: italic +} + +/* Comment.Multiline */ +.dark .codehilite .cp { + color: #79d618; + font-style: italic +} + +/* Comment.Preproc */ +.dark .codehilite .cpf { + color: #79d618; + font-style: italic +} + +/* Comment.PreprocFile */ +.dark .codehilite .c1 { + color: #79d618; + font-style: italic +} + +/* Comment.Single */ +.dark .codehilite .cs { + color: #79d618; + font-style: italic +} + +/* Comment.Special */ +.dark .codehilite .gd { + color: #FF5370 +} + +/* Generic.Deleted */ +.dark .codehilite .ge { + color: #89DDFF +} + +/* Generic.Emph */ +.dark .codehilite .gr { + color: #FF5370 +} + +/* Generic.Error */ +.dark .codehilite .gh { + color: #C3E88D +} + +/* Generic.Heading */ +.dark .codehilite .gi { + color: #C3E88D +} + +/* Generic.Inserted */ +.dark .codehilite .go { + color: #79d618 +} + +/* Generic.Output */ +.dark .codehilite .gp { + color: #FFCB6B +} + +/* Generic.Prompt */ +.dark .codehilite .gs { + color: #FF5370 +} + +/* Generic.Strong */ +.dark .codehilite .gu { + color: #89DDFF +} + +/* Generic.Subheading */ +.dark .codehilite .gt { + color: #FF5370 +} + +/* Generic.Traceback */ +.dark .codehilite .kc { + color: #89DDFF +} + +/* Keyword.Constant */ +.dark .codehilite .kd { + color: #BB80B3 +} + +/* Keyword.Declaration */ +.dark .codehilite .kn { + color: #89DDFF; + font-style: italic +} + +/* Keyword.Namespace */ +.dark .codehilite .kp { + color: #89DDFF +} + +/* Keyword.Pseudo */ +.dark .codehilite .kr { + color: #BB80B3 +} + +/* Keyword.Reserved */ +.dark .codehilite .kt { + color: #BB80B3 +} + +/* Keyword.Type */ +.dark .codehilite .ld { + color: #C3E88D +} + +/* Literal.Date */ +.dark .codehilite .m { + color: #F78C6C +} + +/* Literal.Number */ +.dark .codehilite .s { + color: #C3E88D +} + +/* Literal.String */ +.dark .codehilite .na { + color: #BB80B3 +} + +/* Name.Attribute */ +.dark .codehilite .nb { + color: #82AAFF +} + +/* Name.Builtin */ +.dark .codehilite .nc { + color: #FFCB6B +} + +/* Name.Class */ +.dark .codehilite .no { + color: #EEFFFF +} + +/* Name.Constant */ +.dark .codehilite .nd { + color: #82AAFF +} + +/* Name.Decorator */ +.dark .codehilite .ni { + color: #89DDFF +} + +/* Name.Entity */ +.dark .codehilite .ne { + color: #FFCB6B +} + +/* Name.Exception */ +.dark .codehilite .nf { + color: #82AAFF +} + +/* Name.Function */ +.dark .codehilite .nl { + color: #82AAFF +} + +/* Name.Label */ +.dark .codehilite .nn { + color: #FFCB6B +} + +/* Name.Namespace */ +.dark .codehilite .nx { + color: #EEFFFF +} + +/* Name.Other */ +.dark .codehilite .py { + color: #FFCB6B +} + +/* Name.Property */ +.dark .codehilite .nt { + color: #FF5370 +} + +/* Name.Tag */ +.dark .codehilite .nv { + color: #89DDFF +} + +/* Name.Variable */ +.dark .codehilite .ow { + color: #89DDFF; + font-style: italic +} + +/* Operator.Word */ +.dark .codehilite .pm { + color: #89DDFF +} + +/* Punctuation.Marker */ +.dark .codehilite .w { + color: #EEFFFF +} + +/* Text.Whitespace */ +.dark .codehilite .mb { + color: #F78C6C +} + +/* Literal.Number.Bin */ +.dark .codehilite .mf { + color: #F78C6C +} + +/* Literal.Number.Float */ +.dark .codehilite .mh { + color: #F78C6C +} + +/* Literal.Number.Hex */ +.dark .codehilite .mi { + color: #F78C6C +} + +/* Literal.Number.Integer */ +.dark .codehilite .mo { + color: #F78C6C +} + +/* Literal.Number.Oct */ +.dark .codehilite .sa { + color: #BB80B3 +} + +/* Literal.String.Affix */ +.dark .codehilite .sb { + color: #C3E88D +} + +/* Literal.String.Backtick */ +.dark .codehilite .sc { + color: #C3E88D +} + +/* Literal.String.Char */ +.dark .codehilite .dl { + color: #EEFFFF +} + +/* Literal.String.Delimiter */ +.dark .codehilite .sd { + color: #79d618; + font-style: italic +} + +/* Literal.String.Doc */ +.dark .codehilite .s2 { + color: #C3E88D +} + +/* Literal.String.Double */ +.dark .codehilite .se { + color: #EEFFFF +} + +/* Literal.String.Escape */ +.dark .codehilite .sh { + color: #C3E88D +} + +/* Literal.String.Heredoc */ +.dark .codehilite .si { + color: #89DDFF +} + +/* Literal.String.Interpol */ +.dark .codehilite .sx { + color: #C3E88D +} + +/* Literal.String.Other */ +.dark .codehilite .sr { + color: #89DDFF +} + +/* Literal.String.Regex */ +.dark .codehilite .s1 { + color: #C3E88D +} + +/* Literal.String.Single */ +.dark .codehilite .ss { + color: #89DDFF +} + +/* Literal.String.Symbol */ +.dark .codehilite .bp { + color: #89DDFF +} + +/* Name.Builtin.Pseudo */ +.dark .codehilite .fm { + color: #82AAFF +} + +/* Name.Function.Magic */ +.dark .codehilite .vc { + color: #89DDFF +} + +/* Name.Variable.Class */ +.dark .codehilite .vg { + color: #89DDFF +} + +/* Name.Variable.Global */ +.dark .codehilite .vi { + color: #89DDFF +} + +/* Name.Variable.Instance */ +.dark .codehilite .vm { + color: #82AAFF +} + +/* Name.Variable.Magic */ +.dark .codehilite .il { + color: #F78C6C +} + +/* Literal.Number.Integer.Long */ \ No newline at end of file From 7bf094b6b62cdd7c6dfd0457ba5cb447bd64ab0f Mon Sep 17 00:00:00 2001 From: binary-husky Date: Sat, 7 Dec 2024 22:43:03 +0800 Subject: [PATCH 05/14] remove --- themes/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/common.js b/themes/common.js index f525915e..31ac535a 100644 --- a/themes/common.js +++ b/themes/common.js @@ -1072,7 +1072,7 @@ function reset_conversation(a, b) { setCookie("js_previous_chat_cookie", a, 1); b = btoa(unescape(encodeURIComponent(JSON.stringify(b)))); setCookie("js_previous_history_cookie", b, 1); - gen_restore_btn(); + // gen_restore_btn(); return [[], [], "已重置"]; } From e3f84069eea3ab2f11402086d2d4f61dded29eb3 Mon Sep 17 00:00:00 2001 From: Menghuan Date: Sat, 7 Dec 2024 23:23:59 +0800 Subject: [PATCH 06/14] =?UTF-8?q?=E6=94=B9=E8=BF=9BDoc2X=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E5=A2=9E=E5=8A=A0xelatex=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E7=9A=84=E6=94=AF=E6=8C=81=20(#2058)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * doc2x请求函数格式清理 * 更新中间部分 * 添加doc2x超时设置并添加对xelatex编译的支持 * Bug修复以及增加对xelatex安装的检测 * 增强弱网环境下的稳定性 * 修复模型中_无法显示的问题 * add xelatex logs --------- Co-authored-by: binary-husky --- crazy_functions/PDF_Translate.py | 2 +- crazy_functions/latex_fns/latex_actions.py | 56 +++- .../pdf_fns/parse_pdf_via_doc2x.py | 311 +++++++++++------- main.py | 2 +- 4 files changed, 246 insertions(+), 125 deletions(-) diff --git a/crazy_functions/PDF_Translate.py b/crazy_functions/PDF_Translate.py index 0f93c821..a4d10837 100644 --- a/crazy_functions/PDF_Translate.py +++ b/crazy_functions/PDF_Translate.py @@ -47,7 +47,7 @@ def 批量翻译PDF文档(txt, llm_kwargs, plugin_kwargs, chatbot, history, syst yield from 解析PDF_基于DOC2X(file_manifest, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, DOC2X_API_KEY, user_request) return except: - chatbot.append([None, f"DOC2X服务不可用,现在将执行效果稍差的旧版代码。{trimmed_format_exc_markdown()}"]) + chatbot.append([None, f"DOC2X服务不可用,请检查报错详细。{trimmed_format_exc_markdown()}"]) yield from update_ui(chatbot=chatbot, history=history) if method == "GROBID": diff --git a/crazy_functions/latex_fns/latex_actions.py b/crazy_functions/latex_fns/latex_actions.py index b7dee4ec..ebf7a598 100644 --- a/crazy_functions/latex_fns/latex_actions.py +++ b/crazy_functions/latex_fns/latex_actions.py @@ -300,7 +300,8 @@ def Latex精细分解与转化(file_manifest, project_folder, llm_kwargs, plugin write_html(pfg.sp_file_contents, pfg.sp_file_result, chatbot=chatbot, project_folder=project_folder) # <-------- 写出文件 ----------> - msg = f"当前大语言模型: {llm_kwargs['llm_model']},当前语言模型温度设定: {llm_kwargs['temperature']}。" + model_name = llm_kwargs['llm_model'].replace('_', '\\_') # 替换LLM模型名称中的下划线为转义字符 + msg = f"当前大语言模型: {model_name},当前语言模型温度设定: {llm_kwargs['temperature']}。" final_tex = lps.merge_result(pfg.file_result, mode, msg) objdump((lps, pfg.file_result, mode, msg), file=pj(project_folder,'merge_result.pkl')) @@ -351,6 +352,41 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f chatbot.append([f"正在编译PDF文档", f'编译已经开始。当前工作路径为{work_folder},如果程序停顿5分钟以上,请直接去该路径下取回翻译结果,或者重启之后再度尝试 ...']); yield from update_ui(chatbot=chatbot, history=history) chatbot.append([f"正在编译PDF文档", '...']); yield from update_ui(chatbot=chatbot, history=history); time.sleep(1); chatbot[-1] = list(chatbot[-1]) # 刷新界面 yield from update_ui_lastest_msg('编译已经开始...', chatbot, history) # 刷新Gradio前端界面 + # 检查是否需要使用xelatex + def check_if_need_xelatex(tex_path): + try: + with open(tex_path, 'r', encoding='utf-8', errors='replace') as f: + content = f.read(5000) + # 检查是否有使用xelatex的宏包 + need_xelatex = any( + pkg in content + for pkg in ['fontspec', 'xeCJK', 'xetex', 'unicode-math', 'xltxtra', 'xunicode'] + ) + if need_xelatex: + logger.info(f"检测到宏包需要xelatex编译, 切换至xelatex编译") + else: + logger.info(f"未检测到宏包需要xelatex编译, 使用pdflatex编译") + return need_xelatex + except Exception: + return False + + # 根据编译器类型返回编译命令 + def get_compile_command(compiler, filename): + compile_command = f'{compiler} -interaction=batchmode -file-line-error {filename}.tex' + logger.info('Latex 编译指令: ', compile_command) + return compile_command + + # 确定使用的编译器 + compiler = 'pdflatex' + if check_if_need_xelatex(pj(work_folder_modified, f'{main_file_modified}.tex')): + logger.info("检测到宏包需要xelatex编译,切换至xelatex编译") + # Check if xelatex is installed + try: + import subprocess + subprocess.run(['xelatex', '--version'], capture_output=True, check=True) + compiler = 'xelatex' + except (subprocess.CalledProcessError, FileNotFoundError): + raise RuntimeError("检测到需要使用xelatex编译,但系统中未安装xelatex。请先安装texlive或其他提供xelatex的LaTeX发行版。") while True: import os @@ -361,10 +397,10 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f # https://stackoverflow.com/questions/738755/dont-make-me-manually-abort-a-latex-compile-when-theres-an-error yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 编译原始PDF ...', chatbot, history) # 刷新Gradio前端界面 - ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error {main_file_original}.tex', work_folder_original) + ok = compile_latex_with_timeout(get_compile_command(compiler, main_file_original), work_folder_original) yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 编译转化后的PDF ...', chatbot, history) # 刷新Gradio前端界面 - ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error {main_file_modified}.tex', work_folder_modified) + ok = compile_latex_with_timeout(get_compile_command(compiler, main_file_modified), work_folder_modified) if ok and os.path.exists(pj(work_folder_modified, f'{main_file_modified}.pdf')): # 只有第二步成功,才能继续下面的步骤 @@ -375,10 +411,10 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f ok = compile_latex_with_timeout(f'bibtex {main_file_modified}.aux', work_folder_modified) yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 编译文献交叉引用 ...', chatbot, history) # 刷新Gradio前端界面 - ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error {main_file_original}.tex', work_folder_original) - ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error {main_file_modified}.tex', work_folder_modified) - ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error {main_file_original}.tex', work_folder_original) - ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error {main_file_modified}.tex', work_folder_modified) + ok = compile_latex_with_timeout(get_compile_command(compiler, main_file_original), work_folder_original) + ok = compile_latex_with_timeout(get_compile_command(compiler, main_file_modified), work_folder_modified) + ok = compile_latex_with_timeout(get_compile_command(compiler, main_file_original), work_folder_original) + ok = compile_latex_with_timeout(get_compile_command(compiler, main_file_modified), work_folder_modified) if mode!='translate_zh': yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 使用latexdiff生成论文转化前后对比 ...', chatbot, history) # 刷新Gradio前端界面 @@ -386,10 +422,10 @@ def 编译Latex(chatbot, history, main_file_original, main_file_modified, work_f ok = compile_latex_with_timeout(f'latexdiff --encoding=utf8 --append-safecmd=subfile {work_folder_original}/{main_file_original}.tex {work_folder_modified}/{main_file_modified}.tex --flatten > {work_folder}/merge_diff.tex', os.getcwd()) yield from update_ui_lastest_msg(f'尝试第 {n_fix}/{max_try} 次编译, 正在编译对比PDF ...', chatbot, history) # 刷新Gradio前端界面 - ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error merge_diff.tex', work_folder) + ok = compile_latex_with_timeout(get_compile_command(compiler, 'merge_diff'), work_folder) ok = compile_latex_with_timeout(f'bibtex merge_diff.aux', work_folder) - ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error merge_diff.tex', work_folder) - ok = compile_latex_with_timeout(f'pdflatex -interaction=batchmode -file-line-error merge_diff.tex', work_folder) + ok = compile_latex_with_timeout(get_compile_command(compiler, 'merge_diff'), work_folder) + ok = compile_latex_with_timeout(get_compile_command(compiler, 'merge_diff'), work_folder) # <---------- 检查结果 -----------> results_ = "" diff --git a/crazy_functions/pdf_fns/parse_pdf_via_doc2x.py b/crazy_functions/pdf_fns/parse_pdf_via_doc2x.py index 97c62fbf..93d45b1a 100644 --- a/crazy_functions/pdf_fns/parse_pdf_via_doc2x.py +++ b/crazy_functions/pdf_fns/parse_pdf_via_doc2x.py @@ -6,75 +6,128 @@ from crazy_functions.crazy_utils import get_files_from_everything from shared_utils.colorful import * from loguru import logger import os +import requests import time -def refresh_key(doc2x_api_key): - import requests, json - url = "https://api.doc2x.noedgeai.com/api/token/refresh" - res = requests.post( - url, - headers={"Authorization": "Bearer " + doc2x_api_key} - ) - res_json = [] - if res.status_code == 200: - decoded = res.content.decode("utf-8") - res_json = json.loads(decoded) - doc2x_api_key = res_json['data']['token'] - else: - raise RuntimeError(format("[ERROR] status code: %d, body: %s" % (res.status_code, res.text))) - return doc2x_api_key +def retry_request(max_retries=3, delay=3): + """ + Decorator for retrying HTTP requests + Args: + max_retries: Maximum number of retry attempts + delay: Delay between retries in seconds + """ + + def decorator(func): + def wrapper(*args, **kwargs): + for attempt in range(max_retries): + try: + return func(*args, **kwargs) + except Exception as e: + if attempt < max_retries - 1: + logger.error( + f"Request failed, retrying... ({attempt + 1}/{max_retries}) Error: {e}" + ) + time.sleep(delay) + continue + raise e + return None + + return wrapper + + return decorator + + +@retry_request() +def make_request(method, url, **kwargs): + """ + Make HTTP request with retry mechanism + """ + return requests.request(method, url, **kwargs) + + +def doc2x_api_response_status(response, uid=""): + """ + Check the status of Doc2x API response + Args: + response_data: Response object from Doc2x API + """ + response_json = response.json() + response_data = response_json.get("data", {}) + code = response_json.get("code", "Unknown") + meg = response_data.get("message", response_json) + trace_id = response.headers.get("trace-id", "Failed to get trace-id") + if response.status_code != 200: + raise RuntimeError( + f"Doc2x return an error:\nTrace ID: {trace_id} {uid}\n{response.status_code} - {response_json}" + ) + if code in ["parse_page_limit_exceeded", "parse_concurrency_limit"]: + raise RuntimeError( + f"Reached the limit of Doc2x:\nTrace ID: {trace_id} {uid}\n{code} - {meg}" + ) + if code not in ["ok", "success"]: + raise RuntimeError( + f"Doc2x return an error:\nTrace ID: {trace_id} {uid}\n{code} - {meg}" + ) + return response_data def 解析PDF_DOC2X_转Latex(pdf_file_path): - zip_file_path, unzipped_folder = 解析PDF_DOC2X(pdf_file_path, format='tex') + zip_file_path, unzipped_folder = 解析PDF_DOC2X(pdf_file_path, format="tex") return unzipped_folder -def 解析PDF_DOC2X(pdf_file_path, format='tex'): +def 解析PDF_DOC2X(pdf_file_path, format="tex"): """ - format: 'tex', 'md', 'docx' + format: 'tex', 'md', 'docx' """ - import requests, json, os - DOC2X_API_KEY = get_conf('DOC2X_API_KEY') + + DOC2X_API_KEY = get_conf("DOC2X_API_KEY") latex_dir = get_log_folder(plugin_name="pdf_ocr_latex") markdown_dir = get_log_folder(plugin_name="pdf_ocr") doc2x_api_key = DOC2X_API_KEY + # < ------ 第1步:预上传获取URL,然后上传文件 ------ > + logger.info("Doc2x 上传文件:预上传获取URL") + res = make_request( + "POST", + "https://v2.doc2x.noedgeai.com/api/v2/parse/preupload", + headers={"Authorization": "Bearer " + doc2x_api_key}, + timeout=15, + ) + res_data = doc2x_api_response_status(res) + upload_url = res_data["url"] + uuid = res_data["uid"] - # < ------ 第1步:上传 ------ > - logger.info("Doc2x 第1步:上传") - with open(pdf_file_path, 'rb') as file: - res = requests.post( - "https://v2.doc2x.noedgeai.com/api/v2/parse/pdf", - headers={"Authorization": "Bearer " + doc2x_api_key}, - data=file - ) - # res_json = [] - if res.status_code == 200: - res_json = res.json() - else: - raise RuntimeError(f"Doc2x return an error: {res.json()}") - uuid = res_json['data']['uid'] + logger.info("Doc2x 上传文件:上传文件") + with open(pdf_file_path, "rb") as file: + res = make_request("PUT", upload_url, data=file, timeout=60) + res.raise_for_status() # < ------ 第2步:轮询等待 ------ > - logger.info("Doc2x 第2步:轮询等待") - params = {'uid': uuid} - while True: - res = requests.get( - 'https://v2.doc2x.noedgeai.com/api/v2/parse/status', + logger.info("Doc2x 处理文件中:轮询等待") + params = {"uid": uuid} + max_attempts = 60 + attempt = 0 + while attempt < max_attempts: + res = make_request( + "GET", + "https://v2.doc2x.noedgeai.com/api/v2/parse/status", headers={"Authorization": "Bearer " + doc2x_api_key}, - params=params + params=params, + timeout=15, ) - res_json = res.json() - if res_json['data']['status'] == "success": + res_data = doc2x_api_response_status(res) + if res_data["status"] == "success": break - elif res_json['data']['status'] == "processing": - time.sleep(3) - logger.info(f"Doc2x is processing at {res_json['data']['progress']}%") - elif res_json['data']['status'] == "failed": - raise RuntimeError(f"Doc2x return an error: {res_json}") - + elif res_data["status"] == "processing": + time.sleep(5) + logger.info(f"Doc2x is processing at {res_data['progress']}%") + attempt += 1 + else: + raise RuntimeError(f"Doc2x return an error: {res_data}") + if attempt >= max_attempts: + raise RuntimeError("Doc2x processing timeout after maximum attempts") # < ------ 第3步:提交转化 ------ > logger.info("Doc2x 第3步:提交转化") @@ -84,42 +137,44 @@ def 解析PDF_DOC2X(pdf_file_path, format='tex'): "formula_mode": "dollar", "filename": "output" } - res = requests.post( - 'https://v2.doc2x.noedgeai.com/api/v2/convert/parse', + res = make_request( + "POST", + "https://v2.doc2x.noedgeai.com/api/v2/convert/parse", headers={"Authorization": "Bearer " + doc2x_api_key}, - json=data + json=data, + timeout=15, ) - if res.status_code == 200: - res_json = res.json() - else: - raise RuntimeError(f"Doc2x return an error: {res.json()}") - + doc2x_api_response_status(res, uid=f"uid: {uuid}") # < ------ 第4步:等待结果 ------ > logger.info("Doc2x 第4步:等待结果") - params = {'uid': uuid} - while True: - res = requests.get( - 'https://v2.doc2x.noedgeai.com/api/v2/convert/parse/result', + params = {"uid": uuid} + max_attempts = 36 + attempt = 0 + while attempt < max_attempts: + res = make_request( + "GET", + "https://v2.doc2x.noedgeai.com/api/v2/convert/parse/result", headers={"Authorization": "Bearer " + doc2x_api_key}, - params=params + params=params, + timeout=15, ) - res_json = res.json() - if res_json['data']['status'] == "success": + res_data = doc2x_api_response_status(res, uid=f"uid: {uuid}") + if res_data["status"] == "success": break - elif res_json['data']['status'] == "processing": + elif res_data["status"] == "processing": time.sleep(3) - logger.info(f"Doc2x still processing") - elif res_json['data']['status'] == "failed": - raise RuntimeError(f"Doc2x return an error: {res_json}") - + logger.info("Doc2x still processing to convert file") + attempt += 1 + if attempt >= max_attempts: + raise RuntimeError("Doc2x conversion timeout after maximum attempts") # < ------ 第5步:最后的处理 ------ > - logger.info("Doc2x 第5步:最后的处理") + logger.info("Doc2x 第5步:下载转换后的文件") - if format=='tex': + if format == "tex": target_path = latex_dir - if format=='md': + if format == "md": target_path = markdown_dir os.makedirs(target_path, exist_ok=True) @@ -127,17 +182,18 @@ def 解析PDF_DOC2X(pdf_file_path, format='tex'): # < ------ 下载 ------ > for attempt in range(max_attempt): try: - result_url = res_json['data']['url'] - res = requests.get(result_url) - zip_path = os.path.join(target_path, gen_time_str() + '.zip') + result_url = res_data["url"] + res = make_request("GET", result_url, timeout=60) + zip_path = os.path.join(target_path, gen_time_str() + ".zip") unzip_path = os.path.join(target_path, gen_time_str()) if res.status_code == 200: - with open(zip_path, "wb") as f: f.write(res.content) + with open(zip_path, "wb") as f: + f.write(res.content) else: raise RuntimeError(f"Doc2x return an error: {res.json()}") except Exception as e: if attempt < max_attempt - 1: - logger.error(f"Failed to download latex file, retrying... {e}") + logger.error(f"Failed to download uid = {uuid} file, retrying... {e}") time.sleep(3) continue else: @@ -145,22 +201,31 @@ def 解析PDF_DOC2X(pdf_file_path, format='tex'): # < ------ 解压 ------ > import zipfile - with zipfile.ZipFile(zip_path, 'r') as zip_ref: + with zipfile.ZipFile(zip_path, "r") as zip_ref: zip_ref.extractall(unzip_path) return zip_path, unzip_path -def 解析PDF_DOC2X_单文件(fp, project_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, DOC2X_API_KEY, user_request): - +def 解析PDF_DOC2X_单文件( + fp, + project_folder, + llm_kwargs, + plugin_kwargs, + chatbot, + history, + system_prompt, + DOC2X_API_KEY, + user_request, +): def pdf2markdown(filepath): chatbot.append((None, f"Doc2x 解析中")) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 + yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - md_zip_path, unzipped_folder = 解析PDF_DOC2X(filepath, format='md') + md_zip_path, unzipped_folder = 解析PDF_DOC2X(filepath, format="md") promote_file_to_downloadzone(md_zip_path, chatbot=chatbot) chatbot.append((None, f"完成解析 {md_zip_path} ...")) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 + yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 return md_zip_path def deliver_to_markdown_plugin(md_zip_path, user_request): @@ -174,77 +239,97 @@ def 解析PDF_DOC2X_单文件(fp, project_folder, llm_kwargs, plugin_kwargs, cha os.makedirs(target_path_base, exist_ok=True) shutil.copyfile(md_zip_path, this_file_path) ex_folder = this_file_path + ".extract" - extract_archive( - file_path=this_file_path, dest_dir=ex_folder - ) + extract_archive(file_path=this_file_path, dest_dir=ex_folder) # edit markdown files - success, file_manifest, project_folder = get_files_from_everything(ex_folder, type='.md') + success, file_manifest, project_folder = get_files_from_everything( + ex_folder, type=".md" + ) for generated_fp in file_manifest: # 修正一些公式问题 - with open(generated_fp, 'r', encoding='utf8') as f: + with open(generated_fp, "r", encoding="utf8") as f: content = f.read() # 将公式中的\[ \]替换成$$ - content = content.replace(r'\[', r'$$').replace(r'\]', r'$$') + content = content.replace(r"\[", r"$$").replace(r"\]", r"$$") # 将公式中的\( \)替换成$ - content = content.replace(r'\(', r'$').replace(r'\)', r'$') - content = content.replace('```markdown', '\n').replace('```', '\n') - with open(generated_fp, 'w', encoding='utf8') as f: + content = content.replace(r"\(", r"$").replace(r"\)", r"$") + content = content.replace("```markdown", "\n").replace("```", "\n") + with open(generated_fp, "w", encoding="utf8") as f: f.write(content) promote_file_to_downloadzone(generated_fp, chatbot=chatbot) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 + yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 生成在线预览html - file_name = '在线预览翻译(原文)' + gen_time_str() + '.html' + file_name = "在线预览翻译(原文)" + gen_time_str() + ".html" preview_fp = os.path.join(ex_folder, file_name) - from shared_utils.advanced_markdown_format import markdown_convertion_for_file + from shared_utils.advanced_markdown_format import ( + markdown_convertion_for_file, + ) + with open(generated_fp, "r", encoding="utf-8") as f: md = f.read() # # Markdown中使用不标准的表格,需要在表格前加上一个emoji,以便公式渲染 # md = re.sub(r'^', r'.
', md, flags=re.MULTILINE) html = markdown_convertion_for_file(md) - with open(preview_fp, "w", encoding="utf-8") as f: f.write(html) + with open(preview_fp, "w", encoding="utf-8") as f: + f.write(html) chatbot.append([None, f"生成在线预览:{generate_file_link([preview_fp])}"]) promote_file_to_downloadzone(preview_fp, chatbot=chatbot) - - chatbot.append((None, f"调用Markdown插件 {ex_folder} ...")) - plugin_kwargs['markdown_expected_output_dir'] = ex_folder + plugin_kwargs["markdown_expected_output_dir"] = ex_folder - translated_f_name = 'translated_markdown.md' - generated_fp = plugin_kwargs['markdown_expected_output_path'] = os.path.join(ex_folder, translated_f_name) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 - yield from Markdown英译中(ex_folder, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, user_request) + translated_f_name = "translated_markdown.md" + generated_fp = plugin_kwargs["markdown_expected_output_path"] = os.path.join( + ex_folder, translated_f_name + ) + yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 + yield from Markdown英译中( + ex_folder, + llm_kwargs, + plugin_kwargs, + chatbot, + history, + system_prompt, + user_request, + ) if os.path.exists(generated_fp): # 修正一些公式问题 - with open(generated_fp, 'r', encoding='utf8') as f: content = f.read() - content = content.replace('```markdown', '\n').replace('```', '\n') + with open(generated_fp, "r", encoding="utf8") as f: + content = f.read() + content = content.replace("```markdown", "\n").replace("```", "\n") # Markdown中使用不标准的表格,需要在表格前加上一个emoji,以便公式渲染 # content = re.sub(r'^
', r'.
', content, flags=re.MULTILINE) - with open(generated_fp, 'w', encoding='utf8') as f: f.write(content) + with open(generated_fp, "w", encoding="utf8") as f: + f.write(content) # 生成在线预览html - file_name = '在线预览翻译' + gen_time_str() + '.html' + file_name = "在线预览翻译" + gen_time_str() + ".html" preview_fp = os.path.join(ex_folder, file_name) - from shared_utils.advanced_markdown_format import markdown_convertion_for_file + from shared_utils.advanced_markdown_format import ( + markdown_convertion_for_file, + ) + with open(generated_fp, "r", encoding="utf-8") as f: md = f.read() html = markdown_convertion_for_file(md) - with open(preview_fp, "w", encoding="utf-8") as f: f.write(html) + with open(preview_fp, "w", encoding="utf-8") as f: + f.write(html) promote_file_to_downloadzone(preview_fp, chatbot=chatbot) # 生成包含图片的压缩包 dest_folder = get_log_folder(chatbot.get_user()) - zip_name = '翻译后的带图文档.zip' - zip_folder(source_folder=ex_folder, dest_folder=dest_folder, zip_name=zip_name) + zip_name = "翻译后的带图文档.zip" + zip_folder( + source_folder=ex_folder, dest_folder=dest_folder, zip_name=zip_name + ) zip_fp = os.path.join(dest_folder, zip_name) promote_file_to_downloadzone(zip_fp, chatbot=chatbot) - yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 + yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 + md_zip_path = yield from pdf2markdown(fp) yield from deliver_to_markdown_plugin(md_zip_path, user_request) + def 解析PDF_基于DOC2X(file_manifest, *args): for index, fp in enumerate(file_manifest): yield from 解析PDF_DOC2X_单文件(fp, *args) return - - diff --git a/main.py b/main.py index e54f6d9a..39ad9aeb 100644 --- a/main.py +++ b/main.py @@ -186,7 +186,7 @@ def main(): define_gui_floating_menu(customize_btns, functional, predefined_btns, cookies, web_cookie_cache) # 浮动时间线定义 - gr.Spark(label="", value="") + gr.Spark() # 插件二级菜单的实现 from themes.gui_advanced_plugin_class import define_gui_advanced_plugin_class From 239894544ed9be4f1dbf21a03e352e3c096ebb76 Mon Sep 17 00:00:00 2001 From: Zhenhong Du <61380549+ZhenhongDu@users.noreply.github.com> Date: Sat, 7 Dec 2024 23:41:53 +0800 Subject: [PATCH 07/14] Add support for `grok-beta` model from x.ai (#2060) * Update config.py add support for `grok-beta` model * Update bridge_all.py add support for `grok-beta` model --- config.py | 4 +++- request_llms/bridge_all.py | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/config.py b/config.py index f8e20d70..51f04d22 100644 --- a/config.py +++ b/config.py @@ -55,6 +55,7 @@ EMBEDDING_MODEL = "text-embedding-3-small" # "deepseek-chat" ,"deepseek-coder", # "gemini-1.5-flash", # "yi-34b-chat-0205","yi-34b-chat-200k","yi-large","yi-medium","yi-spark","yi-large-turbo","yi-large-preview", +# "grok-beta", # ] # --- --- --- --- # 此外,您还可以在接入one-api/vllm/ollama/Openroute时, @@ -234,7 +235,6 @@ MOONSHOT_API_KEY = "" # 零一万物(Yi Model) API KEY YIMODEL_API_KEY = "" - # 深度求索(DeepSeek) API KEY,默认请求地址为"https://api.deepseek.com/v1/chat/completions" DEEPSEEK_API_KEY = "" @@ -242,6 +242,8 @@ DEEPSEEK_API_KEY = "" # 紫东太初大模型 https://ai-maas.wair.ac.cn TAICHU_API_KEY = "" +# Grok API KEY +GROK_API_KEY = "" # Mathpix 拥有执行PDF的OCR功能,但是需要注册账号 MATHPIX_APPID = "" diff --git a/request_llms/bridge_all.py b/request_llms/bridge_all.py index 34d05cac..2c3cf14d 100644 --- a/request_llms/bridge_all.py +++ b/request_llms/bridge_all.py @@ -76,6 +76,7 @@ cohere_endpoint = "https://api.cohere.ai/v1/chat" ollama_endpoint = "http://localhost:11434/api/chat" yimodel_endpoint = "https://api.lingyiwanwu.com/v1/chat/completions" deepseekapi_endpoint = "https://api.deepseek.com/v1/chat/completions" +grok_model_endpoint = "https://api.x.ai/v1/chat/completions" if not AZURE_ENDPOINT.endswith('/'): AZURE_ENDPOINT += '/' azure_endpoint = AZURE_ENDPOINT + f'openai/deployments/{AZURE_ENGINE}/chat/completions?api-version=2023-05-15' @@ -97,6 +98,7 @@ if cohere_endpoint in API_URL_REDIRECT: cohere_endpoint = API_URL_REDIRECT[coher if ollama_endpoint in API_URL_REDIRECT: ollama_endpoint = API_URL_REDIRECT[ollama_endpoint] if yimodel_endpoint in API_URL_REDIRECT: yimodel_endpoint = API_URL_REDIRECT[yimodel_endpoint] if deepseekapi_endpoint in API_URL_REDIRECT: deepseekapi_endpoint = API_URL_REDIRECT[deepseekapi_endpoint] +if grok_model_endpoint in API_URL_REDIRECT: grok_model_endpoint = API_URL_REDIRECT[grok_model_endpoint] # 获取tokenizer tokenizer_gpt35 = LazyloadTiktoken("gpt-3.5-turbo") @@ -886,6 +888,31 @@ if any(item in yi_models for item in AVAIL_LLM_MODELS): }) except: logger.error(trimmed_format_exc()) + + +# -=-=-=-=-=-=- Grok model from x.ai -=-=-=-=-=-=- +grok_models = ["grok-beta"] +if any(item in grok_models for item in AVAIL_LLM_MODELS): + try: + grok_beta_128k_noui, grok_beta_128k_ui = get_predict_function( + api_key_conf_name="GROK_API_KEY", max_output_token=8192, disable_proxy=False + ) + + model_info.update({ + "grok-beta": { + "fn_with_ui": grok_beta_128k_ui, + "fn_without_ui": grok_beta_128k_noui, + "can_multi_thread": True, + "endpoint": grok_model_endpoint, + "max_token": 128000, + "tokenizer": tokenizer_gpt35, + "token_cnt": get_token_num_gpt35, + }, + + }) + except: + logger.error(trimmed_format_exc()) + # -=-=-=-=-=-=- 讯飞星火认知大模型 -=-=-=-=-=-=- if "spark" in AVAIL_LLM_MODELS: try: From 294df6c2d5d6f36e1ca009cd9eb8e9f35cd5b218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YE=20Ke=20=E5=8F=B6=E6=9F=AF?= <17290550+YipKo@users.noreply.github.com> Date: Sat, 7 Dec 2024 23:43:51 +0800 Subject: [PATCH 08/14] Add ChatGLM4 local deployment support and refactor ChatGLM bridge's path configuration (#2062) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ feat(request_llms and config.py): ChatGLM4 Deployment Add support for local deployment of ChatGLM4 model * 🦄 refactor(bridge_chatglm3.py): ChatGLM3 model path Added ChatGLM3 path customization (in config.py). Removed useless quantization model options that have been annotated --------- Co-authored-by: MarkDeia <17290550+MarkDeia@users.noreply.github.com> --- README.md | 18 ++++-- config.py | 6 +- request_llms/bridge_all.py | 12 ++++ request_llms/bridge_chatglm3.py | 20 +++---- request_llms/bridge_chatglm4.py | 81 ++++++++++++++++++++++++++ request_llms/requirements_chatglm4.txt | 7 +++ 6 files changed, 124 insertions(+), 20 deletions(-) create mode 100644 request_llms/bridge_chatglm4.py create mode 100644 request_llms/requirements_chatglm4.txt diff --git a/README.md b/README.md index 2b8ffaa5..cf0189ce 100644 --- a/README.md +++ b/README.md @@ -170,26 +170,32 @@ flowchart TD ``` -
如果需要支持清华ChatGLM2/复旦MOSS/RWKV作为后端,请点击展开此处 +
如果需要支持清华ChatGLM系列/复旦MOSS/RWKV作为后端,请点击展开此处

-【可选步骤】如果需要支持清华ChatGLM3/复旦MOSS作为后端,需要额外安装更多依赖(前提条件:熟悉Python + 用过Pytorch + 电脑配置够强): +【可选步骤】如果需要支持清华ChatGLM系列/复旦MOSS作为后端,需要额外安装更多依赖(前提条件:熟悉Python + 用过Pytorch + 电脑配置够强): ```sh # 【可选步骤I】支持清华ChatGLM3。清华ChatGLM备注:如果遇到"Call ChatGLM fail 不能正常加载ChatGLM的参数" 错误,参考如下: 1:以上默认安装的为torch+cpu版,使用cuda需要卸载torch重新安装torch+cuda; 2:如因本机配置不够无法加载模型,可以修改request_llm/bridge_chatglm.py中的模型精度, 将 AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) 都修改为 AutoTokenizer.from_pretrained("THUDM/chatglm-6b-int4", trust_remote_code=True) python -m pip install -r request_llms/requirements_chatglm.txt -# 【可选步骤II】支持复旦MOSS +# 【可选步骤II】支持清华ChatGLM4 注意:此模型至少需要24G显存 +python -m pip install -r request_llms/requirements_chatglm4.txt +# 可使用modelscope下载ChatGLM4模型 +# pip install modelscope +# modelscope download --model ZhipuAI/glm-4-9b-chat --local_dir ./THUDM/glm-4-9b-chat + +# 【可选步骤III】支持复旦MOSS python -m pip install -r request_llms/requirements_moss.txt git clone --depth=1 https://github.com/OpenLMLab/MOSS.git request_llms/moss # 注意执行此行代码时,必须处于项目根路径 -# 【可选步骤III】支持RWKV Runner +# 【可选步骤IV】支持RWKV Runner 参考wiki:https://github.com/binary-husky/gpt_academic/wiki/%E9%80%82%E9%85%8DRWKV-Runner -# 【可选步骤IV】确保config.py配置文件的AVAIL_LLM_MODELS包含了期望的模型,目前支持的全部模型如下(jittorllms系列目前仅支持docker方案): +# 【可选步骤V】确保config.py配置文件的AVAIL_LLM_MODELS包含了期望的模型,目前支持的全部模型如下(jittorllms系列目前仅支持docker方案): AVAIL_LLM_MODELS = ["gpt-3.5-turbo", "api2d-gpt-3.5-turbo", "gpt-4", "api2d-gpt-4", "chatglm", "moss"] # + ["jittorllms_rwkv", "jittorllms_pangualpha", "jittorllms_llama"] -# 【可选步骤V】支持本地模型INT8,INT4量化(这里所指的模型本身不是量化版本,目前deepseek-coder支持,后面测试后会加入更多模型量化选择) +# 【可选步骤VI】支持本地模型INT8,INT4量化(这里所指的模型本身不是量化版本,目前deepseek-coder支持,后面测试后会加入更多模型量化选择) pip install bitsandbyte # windows用户安装bitsandbytes需要使用下面bitsandbytes-windows-webui python -m pip install bitsandbytes --prefer-binary --extra-index-url=https://jllllll.github.io/bitsandbytes-windows-webui diff --git a/config.py b/config.py index 51f04d22..6353cb8a 100644 --- a/config.py +++ b/config.py @@ -36,7 +36,7 @@ AVAIL_LLM_MODELS = ["gpt-4-1106-preview", "gpt-4-turbo-preview", "gpt-4-vision-p "gpt-4o", "gpt-4o-mini", "gpt-4-turbo", "gpt-4-turbo-2024-04-09", "gpt-3.5-turbo-1106", "gpt-3.5-turbo-16k", "gpt-3.5-turbo", "azure-gpt-3.5", "gpt-4", "gpt-4-32k", "azure-gpt-4", "glm-4", "glm-4v", "glm-3-turbo", - "gemini-1.5-pro", "chatglm3" + "gemini-1.5-pro", "chatglm3", "chatglm4" ] EMBEDDING_MODEL = "text-embedding-3-small" @@ -143,6 +143,9 @@ BAIDU_CLOUD_SECRET_KEY = '' BAIDU_CLOUD_QIANFAN_MODEL = 'ERNIE-Bot' # 可选 "ERNIE-Bot-4"(文心大模型4.0), "ERNIE-Bot"(文心一言), "ERNIE-Bot-turbo", "BLOOMZ-7B", "Llama-2-70B-Chat", "Llama-2-13B-Chat", "Llama-2-7B-Chat", "ERNIE-Speed-128K", "ERNIE-Speed-8K", "ERNIE-Lite-8K" +# 如果使用ChatGLM3或ChatGLM4本地模型,请把 LLM_MODEL="chatglm3" 或LLM_MODEL="chatglm4",并在此处指定模型路径 +CHATGLM_LOCAL_MODEL_PATH = "THUDM/glm-4-9b-chat" # 例如"/home/hmp/ChatGLM3-6B/" + # 如果使用ChatGLM2微调模型,请把 LLM_MODEL="chatglmft",并在此处指定模型路径 CHATGLM_PTUNING_CHECKPOINT = "" # 例如"/home/hmp/ChatGLM2-6B/ptuning/output/6b-pt-128-1e-2/checkpoint-100" @@ -375,6 +378,7 @@ DAAS_SERVER_URLS = [ f"https://niuziniu-biligpt{i}.hf.space/stream" for i in ran 本地大模型示意图 │ +├── "chatglm4" ├── "chatglm3" ├── "chatglm" ├── "chatglm_onnx" diff --git a/request_llms/bridge_all.py b/request_llms/bridge_all.py index 2c3cf14d..1aef7089 100644 --- a/request_llms/bridge_all.py +++ b/request_llms/bridge_all.py @@ -26,6 +26,9 @@ from .bridge_chatglm import predict as chatglm_ui from .bridge_chatglm3 import predict_no_ui_long_connection as chatglm3_noui from .bridge_chatglm3 import predict as chatglm3_ui +from .bridge_chatglm4 import predict_no_ui_long_connection as chatglm4_noui +from .bridge_chatglm4 import predict as chatglm4_ui + from .bridge_qianfan import predict_no_ui_long_connection as qianfan_noui from .bridge_qianfan import predict as qianfan_ui @@ -416,6 +419,7 @@ model_info = { "token_cnt": get_token_num_gpt4, }, + # ChatGLM本地模型 # 将 chatglm 直接对齐到 chatglm2 "chatglm": { "fn_with_ui": chatglm_ui, @@ -441,6 +445,14 @@ model_info = { "tokenizer": tokenizer_gpt35, "token_cnt": get_token_num_gpt35, }, + "chatglm4": { + "fn_with_ui": chatglm4_ui, + "fn_without_ui": chatglm4_noui, + "endpoint": None, + "max_token": 8192, + "tokenizer": tokenizer_gpt35, + "token_cnt": get_token_num_gpt35, + }, "qianfan": { "fn_with_ui": qianfan_ui, "fn_without_ui": qianfan_noui, diff --git a/request_llms/bridge_chatglm3.py b/request_llms/bridge_chatglm3.py index 95b629d1..67811858 100644 --- a/request_llms/bridge_chatglm3.py +++ b/request_llms/bridge_chatglm3.py @@ -23,39 +23,33 @@ class GetGLM3Handle(LocalLLMHandle): import os import platform - LOCAL_MODEL_QUANT, device = get_conf("LOCAL_MODEL_QUANT", "LOCAL_MODEL_DEVICE") - _model_name_ = "THUDM/chatglm3-6b" - # if LOCAL_MODEL_QUANT == "INT4": # INT4 - # _model_name_ = "THUDM/chatglm3-6b-int4" - # elif LOCAL_MODEL_QUANT == "INT8": # INT8 - # _model_name_ = "THUDM/chatglm3-6b-int8" - # else: - # _model_name_ = "THUDM/chatglm3-6b" # FP16 + LOCAL_MODEL_PATH, LOCAL_MODEL_QUANT, device = get_conf("CHATGLM_LOCAL_MODEL_PATH", "LOCAL_MODEL_QUANT", "LOCAL_MODEL_DEVICE") + model_path = LOCAL_MODEL_PATH with ProxyNetworkActivate("Download_LLM"): chatglm_tokenizer = AutoTokenizer.from_pretrained( - _model_name_, trust_remote_code=True + model_path, trust_remote_code=True ) if device == "cpu": chatglm_model = AutoModel.from_pretrained( - _model_name_, + model_path, trust_remote_code=True, device="cpu", ).float() elif LOCAL_MODEL_QUANT == "INT4": # INT4 chatglm_model = AutoModel.from_pretrained( - pretrained_model_name_or_path=_model_name_, + pretrained_model_name_or_path=model_path, trust_remote_code=True, quantization_config=BitsAndBytesConfig(load_in_4bit=True), ) elif LOCAL_MODEL_QUANT == "INT8": # INT8 chatglm_model = AutoModel.from_pretrained( - pretrained_model_name_or_path=_model_name_, + pretrained_model_name_or_path=model_path, trust_remote_code=True, quantization_config=BitsAndBytesConfig(load_in_8bit=True), ) else: chatglm_model = AutoModel.from_pretrained( - pretrained_model_name_or_path=_model_name_, + pretrained_model_name_or_path=model_path, trust_remote_code=True, device="cuda", ) diff --git a/request_llms/bridge_chatglm4.py b/request_llms/bridge_chatglm4.py new file mode 100644 index 00000000..1e0ba854 --- /dev/null +++ b/request_llms/bridge_chatglm4.py @@ -0,0 +1,81 @@ +model_name = "ChatGLM4" +cmd_to_install = """ +`pip install -r request_llms/requirements_chatglm4.txt` +`pip install modelscope` +`modelscope download --model ZhipuAI/glm-4-9b-chat --local_dir ./THUDM/glm-4-9b-chat` +""" + + +from toolbox import get_conf, ProxyNetworkActivate +from .local_llm_class import LocalLLMHandle, get_local_llm_predict_fns + + +# ------------------------------------------------------------------------------------------------------------------------ +# 🔌💻 Local Model +# ------------------------------------------------------------------------------------------------------------------------ +class GetGLM4Handle(LocalLLMHandle): + + def load_model_info(self): + # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 + self.model_name = model_name + self.cmd_to_install = cmd_to_install + + def load_model_and_tokenizer(self): + # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 + import torch + from transformers import AutoModel, AutoModelForCausalLM, AutoTokenizer + import os + + LOCAL_MODEL_PATH, device = get_conf("CHATGLM_LOCAL_MODEL_PATH", "LOCAL_MODEL_DEVICE") + model_path = LOCAL_MODEL_PATH + chatglm_tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) + chatglm_model = AutoModelForCausalLM.from_pretrained( + model_path, + torch_dtype=torch.bfloat16, + low_cpu_mem_usage=True, + trust_remote_code=True, + device=device + ).eval().to(device) + self._model = chatglm_model + self._tokenizer = chatglm_tokenizer + return self._model, self._tokenizer + + + def llm_stream_generator(self, **kwargs): + # 🏃‍♂️🏃‍♂️🏃‍♂️ 子进程执行 + def adaptor(kwargs): + query = kwargs["query"] + max_length = kwargs["max_length"] + top_p = kwargs["top_p"] + temperature = kwargs["temperature"] + history = kwargs["history"] + return query, max_length, top_p, temperature, history + + query, max_length, top_p, temperature, history = adaptor(kwargs) + inputs = self._tokenizer.apply_chat_template([{"role": "user", "content": query}], + add_generation_prompt=True, + tokenize=True, + return_tensors="pt", + return_dict=True + ).to(self._model.device) + gen_kwargs = {"max_length": max_length, "do_sample": True, "top_k": top_p} + + outputs = self._model.generate(**inputs, **gen_kwargs) + outputs = outputs[:, inputs['input_ids'].shape[1]:] + response = self._tokenizer.decode(outputs[0], skip_special_tokens=True) + yield response + + def try_to_import_special_deps(self, **kwargs): + # import something that will raise error if the user does not install requirement_*.txt + # 🏃‍♂️🏃‍♂️🏃‍♂️ 主进程执行 + import importlib + + # importlib.import_module('modelscope') + + +# ------------------------------------------------------------------------------------------------------------------------ +# 🔌💻 GPT-Academic Interface +# ------------------------------------------------------------------------------------------------------------------------ +predict_no_ui_long_connection, predict = get_local_llm_predict_fns( + GetGLM4Handle, model_name, history_format="chatglm3" +) diff --git a/request_llms/requirements_chatglm4.txt b/request_llms/requirements_chatglm4.txt new file mode 100644 index 00000000..69cbec29 --- /dev/null +++ b/request_llms/requirements_chatglm4.txt @@ -0,0 +1,7 @@ +protobuf +cpm_kernels +torch>=1.10 +transformers>=4.44 +mdtex2html +sentencepiece +accelerate \ No newline at end of file From c88d8047dd483b44c29e39c93405f8e1bda5e510 Mon Sep 17 00:00:00 2001 From: binary-husky Date: Mon, 9 Dec 2024 23:52:02 +0800 Subject: [PATCH 09/14] cookie storage to local storage --- main.py | 4 ++-- themes/common.js | 19 ++++++++++++------- themes/gui_floating_menu.py | 4 ++-- themes/theme.py | 6 ------ 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/main.py b/main.py index 39ad9aeb..98f0a545 100644 --- a/main.py +++ b/main.py @@ -58,7 +58,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_show_or_hide, js_code_show_or_hide_group2 - from themes.theme import js_code_for_toggle_darkmode, js_code_for_persistent_cookie_init + from themes.theme import js_code_for_toggle_darkmode 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}" @@ -330,7 +330,7 @@ def main(): 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) + outputs = [web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()], _js="""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)) diff --git a/themes/common.js b/themes/common.js index 31ac535a..13158931 100644 --- a/themes/common.js +++ b/themes/common.js @@ -923,12 +923,12 @@ function gpt_academic_gradio_saveload( if (save_or_load === "load") { let value = getCookie(cookie_key); if (value) { - console.log('加载cookie', elem_id, value) + // console.log('加载cookie', elem_id, value) push_data_to_gradio_component(value, elem_id, load_type); } else { if (load_default) { - console.log('加载cookie的默认值', elem_id, load_default_value) + // console.log('加载cookie的默认值', elem_id, load_default_value) push_data_to_gradio_component(load_default_value, elem_id, load_type); } } @@ -950,7 +950,7 @@ function update_conversation_metadata() { setCookie("conversation_metadata", JSON.stringify(conversationData), 2); // read from cookie let conversation_metadata = getCookie("conversation_metadata"); - console.log("conversation_metadata", conversation_metadata); + // console.log("conversation_metadata", conversation_metadata); } // // Example schema for conversation data structure @@ -1040,7 +1040,7 @@ function restore_chat_from_local_storage(event) { let conversation = event.detail; push_data_to_gradio_component(conversation.conversation, "gpt-chatbot", "obj"); push_data_to_gradio_component(conversation.history, "history-ng", "obj"); - console.log("restore_chat_from_local_storage", conversation); + // console.log("restore_chat_from_local_storage", conversation); // Create a conversation UUID and timestamp const conversationId = conversation.id; @@ -1053,7 +1053,7 @@ function restore_chat_from_local_storage(event) { setCookie("conversation_metadata", JSON.stringify(conversationData), 2); // read from cookie let conversation_metadata = getCookie("conversation_metadata"); - console.log("conversation_metadata", conversation_metadata); + // console.log("conversation_metadata", conversation_metadata); } @@ -1193,8 +1193,8 @@ async function on_plugin_exe_complete(fn_name) { } let href = get_href(may_have_chat_profile_info); if (href) { - const cleanedHref = href.replace('file=', ''); // /home/fuqingxu/chatgpt_academic/gpt_log/default_user/chat_history/GPT-Academic对话存档2024-04-12-00-35-06.html - console.log(cleanedHref); + const cleanedHref = href.replace('file=', ''); // gpt_log/default_user/chat_history/GPT-Academic对话存档2024-04-12-00-35-06.html + // console.log(cleanedHref); } } @@ -1492,3 +1492,8 @@ async function run_multiplex_shift(multiplex_sel) { __type__: 'update' }, "elem_submit_visible", "obj"); } + + +async function persistent_cookie_init(web_cookie_cache, cookie) { + return [localStorage.getItem('web_cookie_cache'), cookie]; +} \ No newline at end of file diff --git a/themes/gui_floating_menu.py b/themes/gui_floating_menu.py index 614d9d97..11e14909 100644 --- a/themes/gui_floating_menu.py +++ b/themes/gui_floating_menu.py @@ -35,9 +35,9 @@ def define_gui_floating_menu(customize_btns, functional, predefined_btns, cookie # update btn h = basic_fn_confirm.click(assign_btn, [web_cookie_cache, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix], [web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()]) - h.then(None, [web_cookie_cache], None, _js="""(web_cookie_cache)=>{setCookie("web_cookie_cache", web_cookie_cache, 365);}""") + h.then(None, [web_cookie_cache], None, _js="""(web_cookie_cache)=>{localStorage.setItem("web_cookie_cache", web_cookie_cache);}""") # clean up btn h2 = basic_fn_clean.click(assign_btn, [web_cookie_cache, cookies, basic_btn_dropdown, basic_fn_title, basic_fn_prefix, basic_fn_suffix, gr.State(True)], [web_cookie_cache, cookies, *customize_btns.values(), *predefined_btns.values()]) - h2.then(None, [web_cookie_cache], None, _js="""(web_cookie_cache)=>{setCookie("web_cookie_cache", web_cookie_cache, 365);}""") + h2.then(None, [web_cookie_cache], None, _js="""(web_cookie_cache)=>{localStorage.setItem("web_cookie_cache", web_cookie_cache);}""") return area_input_secondary, txt2, area_customize, submitBtn2, resetBtn2, clearBtn2, stopBtn2 \ No newline at end of file diff --git a/themes/theme.py b/themes/theme.py index 96c3eed6..4ad83e8d 100644 --- a/themes/theme.py +++ b/themes/theme.py @@ -87,12 +87,6 @@ js_code_for_toggle_darkmode = """() => { }""" -js_code_for_persistent_cookie_init = """(web_cookie_cache, cookie) => { - return [getCookie("web_cookie_cache"), cookie]; -} -""" - - js_code_clear = """ (a,b)=>{ return ["", ""]; From 4127162ee770b74cf710ac47e243da4a0b242e38 Mon Sep 17 00:00:00 2001 From: binary-husky Date: Wed, 18 Dec 2024 17:47:23 +0800 Subject: [PATCH 10/14] add tts test --- requirements.txt | 2 +- tests/test_tts.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 tests/test_tts.py diff --git a/requirements.txt b/requirements.txt index f739685d..31ba9157 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,7 +25,7 @@ pyautogen colorama Markdown pygments -edge-tts +edge-tts>=7.0.0 pymupdf openai rjsmin diff --git a/tests/test_tts.py b/tests/test_tts.py new file mode 100644 index 00000000..7d86d1fc --- /dev/null +++ b/tests/test_tts.py @@ -0,0 +1,33 @@ +import edge_tts +import os +import httpx +from toolbox import get_conf + + +async def test_tts(): + async with httpx.AsyncClient() as client: + try: + # Forward the request to the target service + import tempfile + import edge_tts + import wave + import uuid + from pydub import AudioSegment + voice = get_conf("EDGE_TTS_VOICE") + tts = edge_tts.Communicate(text="测试", voice=voice) + temp_folder = tempfile.gettempdir() + temp_file_name = str(uuid.uuid4().hex) + temp_file = os.path.join(temp_folder, f'{temp_file_name}.mp3') + await tts.save(temp_file) + try: + mp3_audio = AudioSegment.from_file(temp_file, format="mp3") + mp3_audio.export(temp_file, format="wav") + with open(temp_file, 'rb') as wav_file: t = wav_file.read() + except: + raise RuntimeError("ffmpeg未安装,无法处理EdgeTTS音频。安装方法见`https://github.com/jiaaro/pydub#getting-ffmpeg-set-up`") + except httpx.RequestError as e: + raise RuntimeError(f"请求失败: {e}") + +if __name__ == "__main__": + import asyncio + asyncio.run(test_tts()) \ No newline at end of file From 81da7bb1a50ed6287a323152a6be0941089f77bd Mon Sep 17 00:00:00 2001 From: binary-husky Date: Wed, 18 Dec 2024 17:48:02 +0800 Subject: [PATCH 11/14] remove welcome card when layout overflows --- themes/welcome.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/themes/welcome.js b/themes/welcome.js index 8296b1f5..e7d86067 100644 --- a/themes/welcome.js +++ b/themes/welcome.js @@ -192,10 +192,22 @@ class WelcomeMessage { async update() { // console.log('update') + const elem_chatbot = document.getElementById('gpt-chatbot'); + const chatbot_top = elem_chatbot.getBoundingClientRect().top; + const welcome_card_container = document.getElementsByClassName('welcome-card-container')[0]; + let welcome_card_overflow = false; + if (welcome_card_container) { + const welcome_card_top = welcome_card_container.getBoundingClientRect().top; + if (welcome_card_top < chatbot_top) { + welcome_card_overflow = true; + // console.log("welcome_card_overflow"); + } + } var page_width = document.documentElement.clientWidth; const width_to_hide_welcome = 1200; - if (!await this.isChatbotEmpty() || page_width < width_to_hide_welcome) { + if (!await this.isChatbotEmpty() || page_width < width_to_hide_welcome || welcome_card_overflow) { if (this.visible) { + // console.log("remove welcome"); this.removeWelcome(); this.visible = false; this.card_array = []; From f43ef909e2c18a8be9d7c5ed5af8e850e30b7e39 Mon Sep 17 00:00:00 2001 From: binary-husky Date: Wed, 18 Dec 2024 22:56:41 +0800 Subject: [PATCH 12/14] roll version to 3.91 --- themes/common.css | 5 +++ themes/common.js | 110 ++++------------------------------------------ version | 4 +- 3 files changed, 15 insertions(+), 104 deletions(-) diff --git a/themes/common.css b/themes/common.css index eb929cff..c28713c1 100644 --- a/themes/common.css +++ b/themes/common.css @@ -270,4 +270,9 @@ } #gpt-submit-row #gpt-submit-dropdown > *:hover { cursor: context-menu; +} + +.tooltip.svelte-p2nen8.svelte-p2nen8 { + box-shadow: 10px 10px 15px rgba(0, 0, 0, 0.5); + left: 10px; } \ No newline at end of file diff --git a/themes/common.js b/themes/common.js index 13158931..038d74cf 100644 --- a/themes/common.js +++ b/themes/common.js @@ -953,26 +953,14 @@ function update_conversation_metadata() { // console.log("conversation_metadata", conversation_metadata); } -// // Example schema for conversation data structure -// const example_conversation = { -// metadata: { -// id: "550e8400-e29b-41d4-a716-446655440000", -// timestamp: "2024-03-29T12:34:56.789Z" -// }, -// conversation: [ -// ["user", "Hello, how are you?"], -// ["assistant", "I'm doing well, thank you for asking! How can I help you today?"], -// ["user", "What is the weather like?"], -// ["assistant", "I don't have access to real-time weather information. You would need to check a weather service or look outside to know the current weather conditions."] -// ], -// preview: "A conversation about greetings and weather" -// } // Helper function to generate conversation preview -function generatePreview(conversation, maxLength = 100) { +function generatePreview(conversation, timestamp, maxLength = 100) { if (!conversation || conversation.length === 0) return ""; // Join all messages with dash separator - const preview = conversation.join("\n"); + let preview = conversation.join("\n"); + const readableDate = new Date(timestamp).toLocaleString(); + preview = readableDate + "\n" + preview; if (preview.length <= maxLength) return preview; return preview.substring(0, maxLength) + "..."; } @@ -990,7 +978,7 @@ async function save_conversation_history() { metadata: conversation_metadata, conversation: chatbot, history: history, - preview: generatePreview(JSON.parse(history)) + preview: generatePreview(JSON.parse(history), conversation_metadata.timestamp) }; // Get existing conversation history from local storage @@ -1036,6 +1024,7 @@ async function save_conversation_history() { } } + function restore_chat_from_local_storage(event) { let conversation = event.detail; push_data_to_gradio_component(conversation.conversation, "gpt-chatbot", "obj"); @@ -1053,7 +1042,6 @@ function restore_chat_from_local_storage(event) { setCookie("conversation_metadata", JSON.stringify(conversationData), 2); // read from cookie let conversation_metadata = getCookie("conversation_metadata"); - // console.log("conversation_metadata", conversation_metadata); } @@ -1066,6 +1054,7 @@ function clear_conversation(a, b, c) { return reset_conversation(a, b); } + function reset_conversation(a, b) { // console.log("js_code_reset"); a = btoa(unescape(encodeURIComponent(JSON.stringify(a)))); @@ -1076,6 +1065,7 @@ function reset_conversation(a, b) { return [[], [], "已重置"]; } + // clear -> 将 history 缓存至 history_cache -> 点击复原 -> restore_previous_chat() -> 触发elem_update_history -> 读取 history_cache function restore_previous_chat() { // console.log("restore_previous_chat"); @@ -1088,90 +1078,6 @@ function restore_previous_chat() { // document.querySelector("#elem_update_history").click(); // in order to call set_history_gr_state, and send history state to server } -function gen_restore_btn() { - - - // 创建按钮元素 - const button = document.createElement('div'); - // const recvIcon = ''; - const rec_svg = '' - const recvIcon = '' + rec_svg + ''; - - // 设置按钮的样式和属性 - button.id = 'floatingButton'; - button.className = 'glow'; - button.style.textAlign = 'center'; - button.style.position = 'fixed'; - button.style.bottom = '10px'; - button.style.left = '10px'; - button.style.width = '50px'; - button.style.height = '50px'; - button.style.borderRadius = '50%'; - button.style.backgroundColor = '#007bff'; - button.style.color = 'white'; - button.style.display = 'flex'; - button.style.alignItems = 'center'; - button.style.justifyContent = 'center'; - button.style.cursor = 'pointer'; - button.style.transition = 'all 0.3s ease'; - button.style.boxShadow = '0 0 10px rgba(0,0,0,0.2)'; - - button.innerHTML = recvIcon; - - // 添加发光动画的关键帧 - const styleSheet = document.createElement('style'); - styleSheet.id = 'floatingButtonStyle'; - styleSheet.innerText = ` - @keyframes glow { - from { - box-shadow: 0 0 10px rgba(0,0,0,0.2); - } - to { - box-shadow: 0 0 13px rgba(0,0,0,0.5); - } - } - #floatingButton.glow { - animation: glow 1s infinite alternate; - } - #floatingButton:hover { - transform: scale(1.2); - box-shadow: 0 0 20px rgba(0,0,0,0.4); - } - #floatingButton.disappearing { - animation: shrinkAndDisappear 0.5s forwards; - } - `; - - // only add when not exist - if (!document.getElementById('recvButtonStyle')) { - document.head.appendChild(styleSheet); - } - - // 鼠标悬停和移开的事件监听器 - button.addEventListener('mouseover', function () { - this.textContent = "还原\n对话"; - }); - - button.addEventListener('mouseout', function () { - this.innerHTML = recvIcon; - }); - - // 点击事件监听器 - button.addEventListener('click', function () { - // 添加一个类来触发缩小和消失的动画 - restore_previous_chat(); - this.classList.add('disappearing'); - // 在动画结束后移除按钮 - document.body.removeChild(this); - }); - // only add when not exist - if (!document.getElementById('recvButton')) { - document.body.appendChild(button); - } - - // 将按钮添加到页面中 - -} async function on_plugin_exe_complete(fn_name) { // console.log(fn_name); diff --git a/version b/version index af84f9b1..2edd3596 100644 --- a/version +++ b/version @@ -1,5 +1,5 @@ { - "version": 3.90, + "version": 3.91, "show_feature": true, - "new_feature": "支持chatgpt-4o-latest <-> 增加RAG组件 <-> 升级多合一主提交键" + "new_feature": "优化前端并修复TTS的BUG <-> 添加时间线回溯功能 <-> 支持chatgpt-4o-latest <-> 增加RAG组件 <-> 升级多合一主提交键" } From 72b2ce9b62f91c31d90e9ea946ac0fa531a7a21c Mon Sep 17 00:00:00 2001 From: binary-husky Date: Wed, 18 Dec 2024 23:05:55 +0800 Subject: [PATCH 13/14] ollama patch --- request_llms/bridge_ollama.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/request_llms/bridge_ollama.py b/request_llms/bridge_ollama.py index 9a2fb97f..c701795f 100644 --- a/request_llms/bridge_ollama.py +++ b/request_llms/bridge_ollama.py @@ -75,7 +75,7 @@ def predict_no_ui_long_connection(inputs, llm_kwargs, history=[], sys_prompt="", # make a POST request to the API endpoint, stream=False from .bridge_all import model_info endpoint = model_info[llm_kwargs['llm_model']]['endpoint'] - response = requests.post(endpoint, headers=headers, proxies=proxies, + response = requests.post(endpoint, headers=headers, proxies=None, json=payload, stream=True, timeout=TIMEOUT_SECONDS); break except requests.exceptions.ReadTimeout as e: retry += 1 @@ -152,10 +152,12 @@ def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_promp history.append(inputs); history.append("") retry = 0 + if proxies is not None: + logger.error("Ollama不会使用代理服务器, 忽略了proxies的设置。") while True: try: # make a POST request to the API endpoint, stream=True - response = requests.post(endpoint, headers=headers, proxies=proxies, + response = requests.post(endpoint, headers=headers, proxies=None, json=payload, stream=True, timeout=TIMEOUT_SECONDS);break except: retry += 1 From 8413fb15ba05c4d1bf245a13096e9a2e03777866 Mon Sep 17 00:00:00 2001 From: binary-husky Date: Wed, 18 Dec 2024 23:35:25 +0800 Subject: [PATCH 14/14] optimize welcome page --- themes/welcome.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/themes/welcome.js b/themes/welcome.js index dfab3daf..24135181 100644 --- a/themes/welcome.js +++ b/themes/welcome.js @@ -96,6 +96,9 @@ class WelcomeMessage { }; const pageFocusHandler = new PageFocusHandler(); pageFocusHandler.addFocusCallback(reflesh_render_status); + + // call update when page size change, call this.update when page size change + window.addEventListener('resize', this.update.bind(this)); } begin_render() { @@ -207,9 +210,8 @@ class WelcomeMessage { const width_to_hide_welcome = 1200; if (!await this.isChatbotEmpty() || page_width < width_to_hide_welcome || welcome_card_overflow) { if (this.visible) { - // console.log("remove welcome"); - this.removeWelcome(); - this.visible = false; + console.log("remove welcome"); + this.removeWelcome(); this.visible = false; // this two lines must always be together this.card_array = []; this.static_welcome_message_previous = []; } @@ -218,9 +220,8 @@ class WelcomeMessage { if (this.visible) { return; } - // console.log("welcome"); - this.showWelcome(); - this.visible = true; + console.log("show welcome"); + this.showWelcome(); this.visible = true; // this two lines must always be together this.startRefleshCards(); }