From e7e1f5901e5f6e1fe98f3947611042beb130296a Mon Sep 17 00:00:00 2001 From: oobabooga <112222186+oobabooga@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:01:43 -0300 Subject: [PATCH] Prompts in the "past chats" menu (#6160) --- css/main.css | 7 ----- js/main.js | 28 ----------------- modules/chat.py | 75 +++++++++++++++++++++++++++++----------------- modules/ui_chat.py | 32 +++----------------- 4 files changed, 52 insertions(+), 90 deletions(-) diff --git a/css/main.css b/css/main.css index 498b3c6c..be73a7cf 100644 --- a/css/main.css +++ b/css/main.css @@ -687,13 +687,6 @@ div.svelte-362y77>*, div.svelte-362y77>.form>* { margin-top: 6px !important; } -/* ---------------------------------------------- - Past chats menus ----------------------------------------------- */ -#rename-row label { - margin-top: var(--layout-gap); -} - /* ---------------------------------------------- Past chat histories in a side bar on desktop ---------------------------------------------- */ diff --git a/js/main.js b/js/main.js index e9a980e2..f8610095 100644 --- a/js/main.js +++ b/js/main.js @@ -488,34 +488,6 @@ function updateDocumentWidth() { updateDocumentWidth(); window.addEventListener("resize", updateDocumentWidth); -//------------------------------------------------ -// Focus on the rename text area when it becomes visible -//------------------------------------------------ -const renameTextArea = document.getElementById("rename-row").querySelector("textarea"); - -function respondToRenameVisibility(element, callback) { - var options = { - root: document.documentElement, - }; - - var observer = new IntersectionObserver((entries, observer) => { - entries.forEach(entry => { - callback(entry.intersectionRatio > 0); - }); - }, options); - - observer.observe(element); -} - - -function handleVisibilityChange(isVisible) { - if (isVisible) { - renameTextArea.focus(); - } -} - -respondToRenameVisibility(renameTextArea, handleVisibilityChange); - //------------------------------------------------ // Adjust the chat tab margin if no extension UI // is present at the bottom diff --git a/modules/chat.py b/modules/chat.py index 5da6ad3b..baa926fd 100644 --- a/modules/chat.py +++ b/modules/chat.py @@ -495,27 +495,9 @@ def save_history(history, unique_id, character, mode): f.write(json.dumps(history, indent=4, ensure_ascii=False)) -def rename_history(old_id, new_id, character, mode): - if shared.args.multi_user: - return - - old_p = get_history_file_path(old_id, character, mode) - new_p = get_history_file_path(new_id, character, mode) - if new_p.parent != old_p.parent: - logger.error(f"The following path is not allowed: \"{new_p}\".") - elif new_p == old_p: - logger.info("The provided path is identical to the old one.") - else: - logger.info(f"Renaming \"{old_p}\" to \"{new_p}\"") - old_p.rename(new_p) - - -def find_all_histories(state): - if shared.args.multi_user: - return [''] - +def get_paths(state): if state['mode'] == 'instruct': - paths = Path('logs/instruct').glob('*.json') + return Path('logs/instruct').glob('*.json') else: character = state['character_menu'] @@ -533,12 +515,51 @@ def find_all_histories(state): p.parent.mkdir(exist_ok=True) new_p.rename(p) - paths = Path(f'logs/chat/{character}').glob('*.json') + return Path(f'logs/chat/{character}').glob('*.json') + +def find_all_histories(state): + if shared.args.multi_user: + return [''] + + paths = get_paths(state) histories = sorted(paths, key=lambda x: x.stat().st_mtime, reverse=True) - histories = [path.stem for path in histories] + return [path.stem for path in histories] - return histories + +def find_all_histories_with_first_prompts(state): + if shared.args.multi_user: + return [] + + paths = get_paths(state) + histories = sorted(paths, key=lambda x: x.stat().st_mtime, reverse=True) + + result = [] + for i, path in enumerate(histories): + filename = path.stem + with open(path, 'r', encoding='utf-8') as f: + data = json.load(f) + if 'visible' in data and len(data['visible']) > 0: + if data['internal'][0][0] == '<|BEGIN-VISIBLE-CHAT|>': + first_prompt = data['visible'][1][0] if len(data['visible']) > 1 else '' + else: + first_prompt = data['visible'][0][0] + + first_prompt = html.unescape(first_prompt) + elif i == 0: + first_prompt = "New chat" + else: + first_prompt = '' + + first_prompt = first_prompt.strip() + + # Truncate the first prompt if it's longer than 32 characters + if len(first_prompt) > 32: + first_prompt = first_prompt[:29] + '...' + + result.append((first_prompt, filename)) + + return result def load_latest_history(state): @@ -569,17 +590,17 @@ def load_history_after_deletion(state, idx): if shared.args.multi_user: return start_new_chat(state) - histories = find_all_histories(state) + histories = find_all_histories_with_first_prompts(state) idx = min(int(idx), len(histories) - 1) idx = max(0, idx) if len(histories) > 0: - history = load_history(histories[idx], state['character_menu'], state['mode']) + history = load_history(histories[idx][1], state['character_menu'], state['mode']) else: history = start_new_chat(state) - histories = find_all_histories(state) + histories = find_all_histories_with_first_prompts - return history, gr.update(choices=histories, value=histories[idx]) + return history, gr.update(choices=histories, value=histories[idx][1]) def update_character_menu_after_deletion(idx): diff --git a/modules/ui_chat.py b/modules/ui_chat.py index d9bf4cb5..b6ca97e2 100644 --- a/modules/ui_chat.py +++ b/modules/ui_chat.py @@ -63,18 +63,11 @@ def create_ui(): with gr.Row(elem_id='past-chats-row', elem_classes=['pretty_scrollbar']): with gr.Column(): with gr.Row(): - 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['delete_chat-confirm'] = gr.Button('Confirm', variant='stop', visible=False, elem_classes=['refresh-button', 'focus-on-chat-input']) shared.gradio['delete_chat-cancel'] = gr.Button('Cancel', visible=False, elem_classes=['refresh-button', 'focus-on-chat-input']) shared.gradio['Start new chat'] = gr.Button('New chat', elem_classes=['refresh-button', 'focus-on-chat-input']) - with gr.Row(elem_id='rename-row'): - shared.gradio['rename_to'] = gr.Textbox(label='Rename to:', placeholder='New name', visible=False, elem_classes=['no-background']) - with gr.Row(): - shared.gradio['rename_to-confirm'] = gr.Button('Confirm', visible=False, elem_classes=['refresh-button', 'focus-on-chat-input']) - shared.gradio['rename_to-cancel'] = gr.Button('Cancel', visible=False, elem_classes=['refresh-button', 'focus-on-chat-input']) - gr.Markdown("Past chats") with gr.Row(): shared.gradio['unique_id'] = gr.Radio(label="", elem_classes=['slim-dropdown', 'pretty_scrollbar'], interactive=not mu, elem_id='past-chats') @@ -254,7 +247,7 @@ def create_event_handlers(): ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( chat.start_new_chat, gradio('interface_state'), gradio('history')).then( chat.redraw_html, gradio(reload_arr), gradio('display')).then( - lambda x: gr.update(choices=(histories := chat.find_all_histories(x)), value=histories[0]), gradio('interface_state'), gradio('unique_id')) + lambda x: gr.update(choices=(histories := chat.find_all_histories_with_first_prompts(x)), value=histories[0][1]), gradio('interface_state'), gradio('unique_id')) shared.gradio['delete_chat'].click(lambda: [gr.update(visible=True), gr.update(visible=False), gr.update(visible=True)], None, gradio(clear_arr)) shared.gradio['delete_chat-cancel'].click(lambda: [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)], None, gradio(clear_arr)) @@ -266,29 +259,12 @@ def create_event_handlers(): chat.redraw_html, gradio(reload_arr), gradio('display')).then( lambda: [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)], None, gradio(clear_arr)) - shared.gradio['rename_chat'].click( - lambda x: x, gradio('unique_id'), gradio('rename_to')).then( - lambda: [gr.update(visible=True)] * 3, None, gradio('rename_to', 'rename_to-confirm', 'rename_to-cancel'), show_progress=False) - - shared.gradio['rename_to-cancel'].click( - lambda: [gr.update(visible=False)] * 3, None, gradio('rename_to', 'rename_to-confirm', 'rename_to-cancel'), show_progress=False) - - shared.gradio['rename_to-confirm'].click( - chat.rename_history, gradio('unique_id', 'rename_to', 'character_menu', 'mode'), None).then( - lambda: [gr.update(visible=False)] * 3, None, gradio('rename_to', 'rename_to-confirm', 'rename_to-cancel'), show_progress=False).then( - lambda x, y: gr.update(choices=chat.find_all_histories(x), value=y), gradio('interface_state', 'rename_to'), gradio('unique_id')) - - shared.gradio['rename_to'].submit( - chat.rename_history, gradio('unique_id', 'rename_to', 'character_menu', 'mode'), None).then( - lambda: [gr.update(visible=False)] * 3, None, gradio('rename_to', 'rename_to-confirm', 'rename_to-cancel'), show_progress=False).then( - lambda x, y: gr.update(choices=chat.find_all_histories(x), value=y), gradio('interface_state', 'rename_to'), gradio('unique_id')) - shared.gradio['load_chat_history'].upload( ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( chat.start_new_chat, gradio('interface_state'), gradio('history')).then( chat.load_history_json, gradio('load_chat_history', 'history'), gradio('history')).then( chat.redraw_html, gradio(reload_arr), gradio('display')).then( - lambda x: gr.update(choices=(histories := chat.find_all_histories(x)), value=histories[0]), gradio('interface_state'), gradio('unique_id')).then( + lambda x: gr.update(choices=(histories := chat.find_all_histories_with_first_prompts(x)), value=histories[0][1]), gradio('interface_state'), gradio('unique_id')).then( chat.save_history, gradio('history', 'unique_id', 'character_menu', 'mode'), None).then( None, None, None, js=f'() => {{{ui.switch_tabs_js}; switch_to_chat()}}') @@ -297,7 +273,7 @@ def create_event_handlers(): ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( chat.load_latest_history, gradio('interface_state'), gradio('history')).then( chat.redraw_html, gradio(reload_arr), gradio('display')).then( - lambda x: gr.update(choices=(histories := chat.find_all_histories(x)), value=histories[0]), gradio('interface_state'), gradio('unique_id')).then( + lambda x: gr.update(choices=(histories := chat.find_all_histories_with_first_prompts(x)), value=histories[0][1]), gradio('interface_state'), gradio('unique_id')).then( None, None, None, js=f'() => {{{ui.update_big_picture_js}; updateBigPicture()}}') shared.gradio['mode'].change( @@ -305,7 +281,7 @@ def create_event_handlers(): ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( chat.load_latest_history, gradio('interface_state'), gradio('history')).then( chat.redraw_html, gradio(reload_arr), gradio('display')).then( - lambda x: gr.update(choices=(histories := chat.find_all_histories(x)), value=histories[0]), gradio('interface_state'), gradio('unique_id')) + lambda x: gr.update(choices=(histories := chat.find_all_histories_with_first_prompts(x)), value=histories[0][1]), gradio('interface_state'), gradio('unique_id')) shared.gradio['chat_style'].change(chat.redraw_html, gradio(reload_arr), gradio('display')) shared.gradio['Copy last reply'].click(chat.send_last_reply_to_input, gradio('history'), gradio('textbox'), show_progress=False)