diff --git a/css/main.css b/css/main.css index 319c1778..d7142336 100644 --- a/css/main.css +++ b/css/main.css @@ -1244,67 +1244,31 @@ div.svelte-362y77>*, div.svelte-362y77>.form>* { position: relative; } -.footer-button { +/* New container for the buttons */ +.message-actions { position: absolute; + bottom: -23px; + left: 0; + display: flex; + gap: 5px; + opacity: 0; + transition: opacity 0.2s; +} + +.footer-button { padding: 0; margin: 0; border: none; border-radius: 3px; cursor: pointer; - opacity: 0; display: flex; align-items: center; - transition: opacity 0.2s; + justify-content: center; } -.footer-button.footer-copy-button { - bottom: -23px; - left: 0; -} - -.footer-button.footer-refresh-button { - bottom: -23px; - left: 25px; -} - -.footer-button.footer-continue-button { - bottom: -23px; - left: 50px; -} - -.footer-button.footer-remove-button { - bottom: -23px; - left: 75px; -} - -.footer-button.footer-info-button { - bottom: -23px; -} - -.user-message .footer-button.footer-info-button { - left: 25px; -} - -.assistant-message:not(:last-child) .footer-button.footer-info-button { - left: 25px; -} - -.assistant-message:last-child .footer-button.footer-info-button { - left: 100px; -} - -.message:not(:last-child) .text-bot .footer-button.footer-info-button, -.message .text-you .footer-button.footer-info-button { - left: 25px; -} - -.message:last-child .text-bot .footer-button.footer-info-button { - left: 100px; -} - -.message:hover .footer-button, -.user-message:hover .footer-button, -.assistant-message:hover .footer-button { +.message:hover .message-actions, +.user-message:hover .message-actions, +.assistant-message:hover .message-actions { opacity: 1; } diff --git a/js/global_scope_js.js b/js/global_scope_js.js index 29d2d8bd..285d82f9 100644 --- a/js/global_scope_js.js +++ b/js/global_scope_js.js @@ -18,6 +18,37 @@ function copyToClipboard(element) { }); } +function branchHere(element) { + if (!element) return; + + const messageElement = element.closest(".message, .user-message, .assistant-message"); + if (!messageElement) return; + + const index = messageElement.getAttribute("data-index"); + if (!index) return; + + const branchIndexInput = document.getElementById("Branch-index").querySelector("input"); + if (!branchIndexInput) { + console.error("Element with ID 'Branch-index' not found."); + return; + } + const branchButton = document.getElementById("Branch"); + + if (!branchButton) { + console.error("Required element 'Branch' not found."); + return; + } + + branchIndexInput.value = index; + + // Trigger any 'change' or 'input' events Gradio might be listening for + const event = new Event("input", { bubbles: true }); // 'change' might also work + branchIndexInput.dispatchEvent(event); + + branchButton.click(); // Gradio will now pick up the 'index' + +} + function regenerateClick() { document.getElementById("Regenerate").click(); } diff --git a/modules/chat.py b/modules/chat.py index cbcde212..13f733e9 100644 --- a/modules/chat.py +++ b/modules/chat.py @@ -1248,7 +1248,13 @@ def handle_delete_chat_confirm_click(state): def handle_branch_chat_click(state): - history = state['history'] + branch_from_index = state['branch_index'] + if branch_from_index == -1: + history = state['history'] + else: + history = state['history'] + history['visible'] = history['visible'][:branch_from_index + 1] + history['internal'] = history['internal'][:branch_from_index + 1] new_unique_id = datetime.now().strftime('%Y%m%d-%H-%M-%S') save_history(history, new_unique_id, state['character_menu'], state['mode']) @@ -1259,7 +1265,7 @@ def handle_branch_chat_click(state): past_chats_update = gr.update(choices=histories, value=new_unique_id) - return [history, html, past_chats_update] + return [history, html, past_chats_update, -1] def handle_rename_chat_click(): diff --git a/modules/html_generator.py b/modules/html_generator.py index 5dbde6da..36b31ac5 100644 --- a/modules/html_generator.py +++ b/modules/html_generator.py @@ -335,10 +335,12 @@ copy_svg = '''''' continue_svg = '''''' remove_svg = '''''' +branch_svg = '''''' info_svg = '''''' info_svg_small = '''''' copy_button = f'' +branch_button = f'' refresh_button = f'' continue_button = f'' remove_button = f'' @@ -355,6 +357,17 @@ def format_message_timestamp(history, role, index): return "" +def actions_html(history, i, info_message=""): + return (f'
' + f'{copy_button}' + f'{refresh_button if i == len(history["visible"]) - 1 else ""}' + f'{continue_button if i == len(history["visible"]) - 1 else ""}' + f'{remove_button if i == len(history["visible"]) - 1 else ""}' + f'{branch_button}' + f'{info_message}' + f'
') + + def generate_instruct_html(history): output = f'
' @@ -386,22 +399,18 @@ def generate_instruct_html(history): f'data-raw="{html.escape(row_internal[0], quote=True)}">' f'
' f'
{converted_visible[0]}
' - f'{copy_button}' - f'{info_message_user}' + f'
{copy_button}{info_message_user}
' f'
' f'
' ) output += ( f'
' + f'data-raw="{html.escape(row_internal[1], quote=True)}"' + f'data-index={i}>' f'
' f'
{converted_visible[1]}
' - f'{copy_button}' - f'{refresh_button if i == len(history["visible"]) - 1 else ""}' - f'{continue_button if i == len(history["visible"]) - 1 else ""}' - f'{remove_button if i == len(history["visible"]) - 1 else ""}' - f'{info_message_assistant}' + f'{actions_html(history, i, info_message_assistant)}' f'
' f'
' ) @@ -441,22 +450,20 @@ def generate_cai_chat_html(history, name1, name2, style, character, reset_cache= f'
' f'
{name1}{user_timestamp}
' f'
{converted_visible[0]}
' - f'{copy_button}' + f'
{copy_button}
' f'
' f'
' ) output += ( f'
' + f'data-raw="{html.escape(row_internal[1], quote=True)}"' + f'data-index={i}>' f'
{img_bot}
' f'
' f'
{name2}{assistant_timestamp}
' f'
{converted_visible[1]}
' - f'{copy_button}' - f'{refresh_button if i == len(history["visible"]) - 1 else ""}' - f'{continue_button if i == len(history["visible"]) - 1 else ""}' - f'{remove_button if i == len(history["visible"]) - 1 else ""}' + f'{actions_html(history, i)}' f'
' f'
' ) @@ -496,22 +503,18 @@ def generate_chat_html(history, name1, name2, reset_cache=False): f'data-raw="{html.escape(row_internal[0], quote=True)}">' f'
' f'
{converted_visible[0]}
' - f'{copy_button}' - f'{info_message_user}' + f'
{copy_button}{info_message_user}
' f'
' f'' ) output += ( f'
' + f'data-raw="{html.escape(row_internal[1], quote=True)}"' + f'data-index={i}>' f'
' f'
{converted_visible[1]}
' - f'{copy_button}' - f'{refresh_button if i == len(history["visible"]) - 1 else ""}' - f'{continue_button if i == len(history["visible"]) - 1 else ""}' - f'{remove_button if i == len(history["visible"]) - 1 else ""}' - f'{info_message_assistant}' + f'{actions_html(history, i, info_message_assistant)}' f'
' f'
' ) diff --git a/modules/ui.py b/modules/ui.py index f5dc0632..5e8fa14e 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -210,6 +210,7 @@ def list_interface_input_elements(): 'negative_prompt', 'dry_sequence_breakers', 'grammar_string', + 'branch_index' ] # Chat elements diff --git a/modules/ui_chat.py b/modules/ui_chat.py index 7a5430ca..513a632b 100644 --- a/modules/ui_chat.py +++ b/modules/ui_chat.py @@ -24,7 +24,8 @@ def create_ui(): with gr.Row(elem_id='past-chats-row', elem_classes=['pretty_scrollbar']): with gr.Column(): with gr.Row(elem_id='past-chats-buttons'): - shared.gradio['branch_chat'] = gr.Button('Branch', elem_classes='refresh-button', interactive=not mu) + shared.gradio['branch_chat'] = gr.Button('Branch', elem_classes='refresh-button', elem_id='Branch', interactive=not mu) + shared.gradio['branch_index'] = gr.Number(value=-1, precision=0, visible=False, elem_id="Branch-index", interactive=True) shared.gradio['rename_chat'] = gr.Button('Rename', elem_classes='refresh-button', interactive=not mu) shared.gradio['delete_chat'] = gr.Button('🗑️', elem_classes='refresh-button', interactive=not mu) shared.gradio['Start new chat'] = gr.Button('New chat', elem_classes=['refresh-button', 'focus-on-chat-input']) @@ -258,7 +259,7 @@ def create_event_handlers(): shared.gradio['branch_chat'].click( ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( - chat.handle_branch_chat_click, gradio('interface_state'), gradio('history', 'display', 'unique_id'), show_progress=False) + chat.handle_branch_chat_click, gradio('interface_state'), gradio('history', 'display', 'unique_id', 'branch_index'), show_progress=False) shared.gradio['rename_chat'].click(chat.handle_rename_chat_click, None, gradio('rename_to', 'rename-row'), show_progress=False) shared.gradio['rename_to-cancel'].click(lambda: gr.update(visible=False), None, gradio('rename-row'), show_progress=False)