diff --git a/main.py b/main.py index 73a3e2b8..062cba5f 100644 --- a/main.py +++ b/main.py @@ -184,7 +184,7 @@ 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() diff --git a/shared_utils/advanced_markdown_format.py b/shared_utils/advanced_markdown_format.py index 7be1db20..a8a10411 100644 --- a/shared_utils/advanced_markdown_format.py +++ b/shared_utils/advanced_markdown_format.py @@ -347,7 +347,7 @@ def markdown_convertion(txt): # 在文本中插入一个base64编码的原始文本,以便在复制时能够获得原始文本 raw_text_encoded = compress_string(txt) - raw_text_node = f'' + raw_text_node = f'" # 用于查找数学公式的正则表达式 diff --git a/themes/common.css b/themes/common.css index 2f7dda2f..610d46c2 100644 --- a/themes/common.css +++ b/themes/common.css @@ -335,4 +335,74 @@ .raw_text { display: none; +} + +.message_tail { + justify-content: center; + align-items: center; +} +.message_tail_stop { + border: dotted !important; + margin-top: 5px !important; + padding-left: 8px !important; + padding-top: 1px !important; + padding-bottom: 1px !important; + padding-right: 12px !important; +} + +/* ant 开始 */ + +/* 通用按钮样式 */ +.ant-btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 8px 16px; + font-size: 14px; + font-weight: bold; + border-radius: 4px; + cursor: pointer; + transition: background-color 0.3s; +} + +/* 按钮颜色和状态 */ +.ant-btn-primary { + background-color: #1890ff; + color: white; + border: none; +} + +.ant-btn-primary:hover { + background-color: #40a9ff; +} + +.ant-btn-loading { + pointer-events: none; + opacity: 0.7; +} + +/* 图标样式 */ +.ant-btn-icon { + display: inline-flex; + margin-right: 8px; +} + +.anticon { + width: 1em; + height: 1em; + fill: currentColor; +} + +.anticon-spin { + animation: spin 1s linear infinite; +} + +/* 动画效果 */ +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } } \ No newline at end of file diff --git a/themes/common.js b/themes/common.js index f8510624..f05b9b71 100644 --- a/themes/common.js +++ b/themes/common.js @@ -289,7 +289,7 @@ function addCopyButton(botElement, index, is_last_in_arr) { const audioIcon = ''; // const cancelAudioIcon = ''; - // 此功能没准备好 + // audio functionality if (allow_auto_read_continously && is_last_in_arr && allow_auto_read_tts_flag) { process_latest_text_output(botElement.innerText, index); } @@ -300,41 +300,6 @@ function addCopyButton(botElement, index, is_last_in_arr) { return; } - // var copyButton = document.createElement('button'); - // copyButton.classList.add('copy-bot-btn'); - // copyButton.setAttribute('aria-label', 'Copy'); - // copyButton.innerHTML = copyIcon; - // copyButton.addEventListener('click', async () => { - // const textToCopy = botElement.innerText; - // try { - // // push_text_to_audio(textToCopy).catch(console.error); - // if ("clipboard" in navigator) { - // await navigator.clipboard.writeText(textToCopy); - // copyButton.innerHTML = copiedIcon; - // setTimeout(() => { - // copyButton.innerHTML = copyIcon; - // }, 1500); - // } else { - // const textArea = document.createElement("textarea"); - // textArea.value = textToCopy; - // document.body.appendChild(textArea); - // textArea.select(); - // try { - // document.execCommand('copy'); - // copyButton.innerHTML = copiedIcon; - // setTimeout(() => { - // copyButton.innerHTML = copyIcon; - // }, 1500); - // } catch (error) { - // console.error("Copy failed: ", error); - // } - // document.body.removeChild(textArea); - // } - // } catch (error) { - // console.error("Copy failed: ", error); - // } - // }); - // 原始文本拷贝 var copyButtonOrig = document.createElement('button'); copyButtonOrig.classList.add('copy-bot-btn'); @@ -436,7 +401,6 @@ function do_something_but_not_too_frequently(min_interval, func) { function chatbotContentChanged(attempt = 1, force = false) { - // https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript for (var i = 0; i < attempt; i++) { setTimeout(() => { const messages = gradioApp().querySelectorAll('#gpt-chatbot .message-wrap .message.bot'); @@ -447,6 +411,9 @@ 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); + // if last message, add stop btn link + addStopButton(message, index, is_last_in_arr); + // save_conversation_history save_conversation_history_slow_down(); }); @@ -457,6 +424,79 @@ function chatbotContentChanged(attempt = 1, force = false) { } +function addStopButton(botElement, index, is_last_in_arr) { + function is_generating() { + var statePanelElement = document.getElementById("state-panel"); + var generatingElement = statePanelElement.querySelector(".generating"); + if (generatingElement) { + return true; + } else { + return false; + } + } + function on_stop_btn_click() { + let stopButton = document.getElementById("elem_stop"); + stopButton.click(); + } + function remove_stop_generate_btn(messageTailElement) { + // remove all child elements of messageTailElement + while (messageTailElement.firstChild) { + messageTailElement.removeChild(messageTailElement.firstChild); + } + messageTailElement.style.display = 'none'; + messageTailElement.classList.add('removed'); + } + function add_stop_generate_btn() { + // write here: add a beautiful stop btn `bottomElement` as child, when clicked execute on_stop_btn_click + console.log("get_gradio_component") + const bottomElement = document.createElement('button'); + bottomElement.className = 'ant-btn ant-btn-primary'; + bottomElement.innerHTML = ` + + + + 终止 + `; + bottomElement.classList.add('message_tail_stop'); + bottomElement.addEventListener('click', on_stop_btn_click); + messageTailElement.appendChild(bottomElement); + } + + // find a sub element of class `message_tail` + const messageTailElement = botElement.querySelector('.message_tail'); + // if not is_last_in_arr, hide this elem (display none) + if (!messageTailElement) { + return; + } + if (messageTailElement.classList.contains('removed')) { + return; + } + if (!is_last_in_arr) { + remove_stop_generate_btn(messageTailElement); + return; + } + messageTailElement.style.display = 'flex'; + const messageTailStopElem = messageTailElement.querySelector('.message_tail_stop'); + if(!is_generating()) { + setTimeout(() => { + if(!is_generating()) { + remove_stop_generate_btn(messageTailElement); + return; + } else { + if (!messageTailStopElem) { + add_stop_generate_btn() + } + } + }, 500); + } else { + if (!messageTailStopElem) { + add_stop_generate_btn() + } + } + +} // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=