Skip to content

Commit 858b5f6

Browse files
committed
add in-text stop btn
1 parent 63c61e6 commit 858b5f6

File tree

4 files changed

+149
-39
lines changed

4 files changed

+149
-39
lines changed

main.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ def main():
184184
from themes.gui_floating_menu import define_gui_floating_menu
185185
area_input_secondary, txt2, area_customize, _, resetBtn2, clearBtn2, stopBtn2 = \
186186
define_gui_floating_menu(customize_btns, functional, predefined_btns, cookies, web_cookie_cache)
187-
187+
188188
# 浮动时间线定义
189189
gr.Spark()
190190

shared_utils/advanced_markdown_format.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ def markdown_convertion(txt):
347347

348348
# 在文本中插入一个base64编码的原始文本,以便在复制时能够获得原始文本
349349
raw_text_encoded = compress_string(txt)
350-
raw_text_node = f'<div class="raw_text" style="display:none">{raw_text_encoded}</div>'
350+
raw_text_node = f'<div class="raw_text" style="display:none">{raw_text_encoded}</div><div class="message_tail" style="display:none"/>'
351351
suf = raw_text_node + "</div>"
352352

353353
# 用于查找数学公式的正则表达式

themes/common.css

+70
Original file line numberDiff line numberDiff line change
@@ -335,4 +335,74 @@
335335

336336
.raw_text {
337337
display: none;
338+
}
339+
340+
.message_tail {
341+
justify-content: center;
342+
align-items: center;
343+
}
344+
.message_tail_stop {
345+
border: dotted !important;
346+
margin-top: 5px !important;
347+
padding-left: 8px !important;
348+
padding-top: 1px !important;
349+
padding-bottom: 1px !important;
350+
padding-right: 12px !important;
351+
}
352+
353+
/* ant 开始 */
354+
355+
/* 通用按钮样式 */
356+
.ant-btn {
357+
display: inline-flex;
358+
align-items: center;
359+
justify-content: center;
360+
padding: 8px 16px;
361+
font-size: 14px;
362+
font-weight: bold;
363+
border-radius: 4px;
364+
cursor: pointer;
365+
transition: background-color 0.3s;
366+
}
367+
368+
/* 按钮颜色和状态 */
369+
.ant-btn-primary {
370+
background-color: #1890ff;
371+
color: white;
372+
border: none;
373+
}
374+
375+
.ant-btn-primary:hover {
376+
background-color: #40a9ff;
377+
}
378+
379+
.ant-btn-loading {
380+
pointer-events: none;
381+
opacity: 0.7;
382+
}
383+
384+
/* 图标样式 */
385+
.ant-btn-icon {
386+
display: inline-flex;
387+
margin-right: 8px;
388+
}
389+
390+
.anticon {
391+
width: 1em;
392+
height: 1em;
393+
fill: currentColor;
394+
}
395+
396+
.anticon-spin {
397+
animation: spin 1s linear infinite;
398+
}
399+
400+
/* 动画效果 */
401+
@keyframes spin {
402+
from {
403+
transform: rotate(0deg);
404+
}
405+
to {
406+
transform: rotate(360deg);
407+
}
338408
}

themes/common.js

+77-37
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ function addCopyButton(botElement, index, is_last_in_arr) {
289289
const audioIcon = '<span><svg t="1713628577799" fill="currentColor" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4587" width=".9em" height=".9em"><path d="M113.7664 540.4672c0-219.9552 178.2784-398.2336 398.2336-398.2336S910.2336 320.512 910.2336 540.4672v284.4672c0 31.4368-25.4976 56.9344-56.9344 56.9344h-56.9344c-31.4368 0-56.9344-25.4976-56.9344-56.9344V597.2992c0-31.4368 25.4976-56.9344 56.9344-56.9344h56.9344c0-188.5184-152.7808-341.2992-341.2992-341.2992S170.7008 351.9488 170.7008 540.4672h56.9344c31.4368 0 56.9344 25.4976 56.9344 56.9344v227.5328c0 31.4368-25.4976 56.9344-56.9344 56.9344h-56.9344c-31.4368 0-56.9344-25.4976-56.9344-56.9344V540.4672z" p-id="4588"></path></svg></span>';
290290
// const cancelAudioIcon = '<span><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height=".8em" width=".8em" xmlns="http://www.w3.org/2000/svg"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></span>';
291291

292-
// 此功能没准备好
292+
// audio functionality
293293
if (allow_auto_read_continously && is_last_in_arr && allow_auto_read_tts_flag) {
294294
process_latest_text_output(botElement.innerText, index);
295295
}
@@ -300,41 +300,6 @@ function addCopyButton(botElement, index, is_last_in_arr) {
300300
return;
301301
}
302302

303-
// var copyButton = document.createElement('button');
304-
// copyButton.classList.add('copy-bot-btn');
305-
// copyButton.setAttribute('aria-label', 'Copy');
306-
// copyButton.innerHTML = copyIcon;
307-
// copyButton.addEventListener('click', async () => {
308-
// const textToCopy = botElement.innerText;
309-
// try {
310-
// // push_text_to_audio(textToCopy).catch(console.error);
311-
// if ("clipboard" in navigator) {
312-
// await navigator.clipboard.writeText(textToCopy);
313-
// copyButton.innerHTML = copiedIcon;
314-
// setTimeout(() => {
315-
// copyButton.innerHTML = copyIcon;
316-
// }, 1500);
317-
// } else {
318-
// const textArea = document.createElement("textarea");
319-
// textArea.value = textToCopy;
320-
// document.body.appendChild(textArea);
321-
// textArea.select();
322-
// try {
323-
// document.execCommand('copy');
324-
// copyButton.innerHTML = copiedIcon;
325-
// setTimeout(() => {
326-
// copyButton.innerHTML = copyIcon;
327-
// }, 1500);
328-
// } catch (error) {
329-
// console.error("Copy failed: ", error);
330-
// }
331-
// document.body.removeChild(textArea);
332-
// }
333-
// } catch (error) {
334-
// console.error("Copy failed: ", error);
335-
// }
336-
// });
337-
338303
// 原始文本拷贝
339304
var copyButtonOrig = document.createElement('button');
340305
copyButtonOrig.classList.add('copy-bot-btn');
@@ -436,7 +401,6 @@ function do_something_but_not_too_frequently(min_interval, func) {
436401

437402

438403
function chatbotContentChanged(attempt = 1, force = false) {
439-
// https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript
440404
for (var i = 0; i < attempt; i++) {
441405
setTimeout(() => {
442406
const messages = gradioApp().querySelectorAll('#gpt-chatbot .message-wrap .message.bot');
@@ -447,6 +411,9 @@ function chatbotContentChanged(attempt = 1, force = false) {
447411
// Now pass both the message element and the is_last_in_arr boolean to addCopyButton
448412
addCopyButton(message, index, is_last_in_arr);
449413

414+
// if last message, add stop btn link
415+
addStopButton(message, index, is_last_in_arr);
416+
450417
// save_conversation_history
451418
save_conversation_history_slow_down();
452419
});
@@ -457,6 +424,79 @@ function chatbotContentChanged(attempt = 1, force = false) {
457424

458425
}
459426

427+
function addStopButton(botElement, index, is_last_in_arr) {
428+
function is_generating() {
429+
var statePanelElement = document.getElementById("state-panel");
430+
var generatingElement = statePanelElement.querySelector(".generating");
431+
if (generatingElement) {
432+
return true;
433+
} else {
434+
return false;
435+
}
436+
}
437+
function on_stop_btn_click() {
438+
let stopButton = document.getElementById("elem_stop");
439+
stopButton.click();
440+
}
441+
function remove_stop_generate_btn(messageTailElement) {
442+
// remove all child elements of messageTailElement
443+
while (messageTailElement.firstChild) {
444+
messageTailElement.removeChild(messageTailElement.firstChild);
445+
}
446+
messageTailElement.style.display = 'none';
447+
messageTailElement.classList.add('removed');
448+
}
449+
function add_stop_generate_btn() {
450+
// write here: add a beautiful stop btn `bottomElement` as child, when clicked execute on_stop_btn_click
451+
console.log("get_gradio_component")
452+
const bottomElement = document.createElement('button');
453+
bottomElement.className = 'ant-btn ant-btn-primary';
454+
bottomElement.innerHTML = `
455+
<span class="ant-btn-icon">
456+
<svg viewBox="64 64 896 896" focusable="false" data-icon="sync" width="1em" height="1em" fill="currentColor" aria-hidden="true" class="anticon anticon-sync anticon-spin">
457+
<path d="M168 504.2c1-43.7 10-86.1 26.9-126 17.3-41 42.1-77.7 73.7-109.4S337 212.3 378 195c42.4-17.9 87.4-27 133.9-27s91.5 9.1 133.8 27A341.5 341.5 0 01755 268.8c9.9 9.9 19.2 20.4 27.8 31.4l-60.2 47a8 8 0 003 14.1l175.7 43c5 1.2 9.9-2.6 9.9-7.7l.8-180.9c0-6.7-7.7-10.5-12.9-6.3l-56.4 44.1C765.8 155.1 646.2 92 511.8 92 282.7 92 96.3 275.6 92 503.8a8 8 0 008 8.2h60c4.4 0 7.9-3.5 8-7.8zm756 7.8h-60c-4.4 0-7.9 3.5-8 7.8-1 43.7-10 86.1-26.9 126-17.3 41-42.1 77.8-73.7 109.4A342.45 342.45 0 01512.1 856a342.24 342.24 0 01-243.2-100.8c-9.9-9.9-19.2-20.4-27.8-31.4l60.2-47a8 8 0 00-3-14.1l-175.7-43c-5-1.2-9.9 2.6-9.9 7.7l-.7 181c0 6.7 7.7 10.5 12.9 6.3l56.4-44.1C258.2 868.9 377.8 932 512.2 932c229.2 0 415.5-183.7 419.8-411.8a8 8 0 00-8-8.2z"></path>
458+
</svg>
459+
</span>
460+
<span>终止</span>
461+
`;
462+
bottomElement.classList.add('message_tail_stop');
463+
bottomElement.addEventListener('click', on_stop_btn_click);
464+
messageTailElement.appendChild(bottomElement);
465+
}
466+
467+
// find a sub element of class `message_tail`
468+
const messageTailElement = botElement.querySelector('.message_tail');
469+
// if not is_last_in_arr, hide this elem (display none)
470+
if (!messageTailElement) {
471+
return;
472+
}
473+
if (messageTailElement.classList.contains('removed')) {
474+
return;
475+
}
476+
if (!is_last_in_arr) {
477+
remove_stop_generate_btn(messageTailElement);
478+
return;
479+
}
480+
messageTailElement.style.display = 'flex';
481+
const messageTailStopElem = messageTailElement.querySelector('.message_tail_stop');
482+
if(!is_generating()) {
483+
setTimeout(() => {
484+
if(!is_generating()) {
485+
remove_stop_generate_btn(messageTailElement);
486+
return;
487+
} else {
488+
if (!messageTailStopElem) {
489+
add_stop_generate_btn()
490+
}
491+
}
492+
}, 500);
493+
} else {
494+
if (!messageTailStopElem) {
495+
add_stop_generate_btn()
496+
}
497+
}
498+
499+
}
460500

461501

462502
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

0 commit comments

Comments
 (0)