diff --git a/characters/Assistant.yaml b/characters/Assistant.yaml new file mode 100644 index 00000000..c313ebc6 --- /dev/null +++ b/characters/Assistant.yaml @@ -0,0 +1,4 @@ +name: AI +greeting: I have the entire internet compressed into my neural network weights. What would you like to know? +context: | + The following is a conversation with an AI Large Language Model. The AI has been trained to answer questions, provide recommendations, and help with decision making. The AI follows user requests. The AI thinks outside the box. diff --git a/js/main.js b/js/main.js index f4e20f89..ebbada71 100644 --- a/js/main.js +++ b/js/main.js @@ -244,11 +244,9 @@ if (buttonsInChat.length > 0) { const thisButton = buttonsInChat[i]; menu.appendChild(thisButton); - if(i != 8) { - thisButton.addEventListener("click", () => { - hideMenu(); - }); - } + thisButton.addEventListener("click", () => { + hideMenu(); + }); const buttonText = thisButton.textContent; const matches = buttonText.match(/(\(.*?\))/); diff --git a/modules/chat.py b/modules/chat.py index e3745d0b..2b04dec6 100644 --- a/modules/chat.py +++ b/modules/chat.py @@ -4,6 +4,7 @@ import functools import html import json import re +from datetime import datetime from pathlib import Path import gradio as gr @@ -297,8 +298,25 @@ def generate_chat_reply(text, state, regenerate=False, _continue=False, loading_ yield history -# Same as above but returns HTML for the UI +def character_is_loaded(state, raise_exception=False): + if state['mode'] in ['chat', 'chat-instruct'] and state['name2'] == '': + logger.error('It looks like no character is loaded. Please load one under Parameters > Character.') + if raise_exception: + raise ValueError + + return False + else: + return True + + def generate_chat_reply_wrapper(text, state, regenerate=False, _continue=False): + ''' + Same as above but returns HTML for the UI + ''' + + if not character_is_loaded(state): + return + if state['start_with'] != '' and not _continue: if regenerate: text, state['history'] = remove_last_message(state['history']) @@ -359,86 +377,132 @@ def send_dummy_reply(text, state): return history -def clear_chat_log(state): - greeting = replace_character_names(state['greeting'], state['name1'], state['name2']) - mode = state['mode'] - history = state['history'] - - history['visible'] = [] - history['internal'] = [] - if mode != 'instruct': - if greeting != '': - history['internal'] += [['<|BEGIN-VISIBLE-CHAT|>', greeting]] - history['visible'] += [['', apply_extensions('output', greeting, state, is_chat=True)]] - - return history - - def redraw_html(history, name1, name2, mode, style, reset_cache=False): return chat_html_wrapper(history, name1, name2, mode, style, reset_cache=reset_cache) -def save_history(history, path=None): - p = path or Path('logs/exported_history.json') +def start_new_chat(state): + mode = state['mode'] + history = {'internal': [], 'visible': []} + + if mode != 'instruct': + greeting = replace_character_names(state['greeting'], state['name1'], state['name2']) + if greeting != '': + history['internal'] += [['<|BEGIN-VISIBLE-CHAT|>', greeting]] + history['visible'] += [['', apply_extensions('output', greeting, state, is_chat=True)]] + + unique_id = datetime.now().strftime('%Y%m%d-%H-%M-%S') + save_history(history, unique_id, state['character_menu'], state['mode']) + + return history + + +def get_history_file_path(unique_id, character, mode): + if mode == 'instruct': + p = Path(f'logs/instruct/{unique_id}.json') + else: + p = Path(f'logs/chat/{character}/{unique_id}.json') + + return p + + +def save_history(history, unique_id, character, mode): + if shared.args.multi_user: + return + + p = get_history_file_path(unique_id, character, mode) if not p.parent.is_dir(): p.parent.mkdir(parents=True) with open(p, 'w', encoding='utf-8') as f: f.write(json.dumps(history, indent=4)) - return p + +def find_all_histories(state): + if shared.args.multi_user: + return [''] + + if state['mode'] == 'instruct': + paths = Path('logs/instruct').glob('*.json') + else: + character = state['character_menu'] + + # Handle obsolete filenames and paths + old_p = Path(f'logs/{character}_persistent.json') + new_p = Path(f'logs/persistent_{character}.json') + if old_p.exists(): + logger.warning(f"Renaming {old_p} to {new_p}") + old_p.rename(new_p) + if new_p.exists(): + unique_id = datetime.now().strftime('%Y%m%d-%H-%M-%S') + p = get_history_file_path(unique_id, character, state['mode']) + logger.warning(f"Moving {new_p} to {p}") + p.parent.mkdir(exist_ok=True) + new_p.rename(p) + + paths = Path(f'logs/chat/{character}').glob('*.json') + + histories = sorted(paths, key=lambda x: x.stat().st_mtime, reverse=True) + histories = [path.stem for path in histories] + + return histories -def load_history(file, history): +def load_latest_history(state): + ''' + Loads the latest history for the given character in chat or chat-instruct + mode, or the latest instruct history for instruct mode. + ''' + + if shared.args.multi_user: + return start_new_chat(state) + + histories = find_all_histories(state) + + if len(histories) > 0: + unique_id = Path(histories[0]).stem + history = load_history(unique_id, state['character_menu'], state['mode']) + else: + history = start_new_chat(state) + + return history + + +def load_history(unique_id, character, mode): + p = get_history_file_path(unique_id, character, mode) + + f = json.loads(open(p, 'rb').read()) + if 'internal' in f and 'visible' in f: + history = f + else: + history = { + 'internal': f['data'], + 'visible': f['data_visible'] + } + + return history + + +def load_history_json(file, history): try: file = file.decode('utf-8') - j = json.loads(file) - if 'internal' in j and 'visible' in j: - return j + f = json.loads(file) + if 'internal' in f and 'visible' in f: + history = f else: - return history + history = { + 'internal': f['data'], + 'visible': f['data_visible'] + } + + return history except: return history -def save_persistent_history(history, character, mode): - if mode in ['chat', 'chat-instruct'] and character not in ['', 'None', None] and not shared.args.multi_user: - save_history(history, path=Path(f'logs/persistent_{character}.json')) - - -def load_persistent_history(state): - if shared.session_is_loading: - shared.session_is_loading = False - return state['history'] - - if state['mode'] == 'instruct': - return state['history'] - - character = state['character_menu'] - greeting = replace_character_names(state['greeting'], state['name1'], state['name2']) - - should_load_history = (not shared.args.multi_user and character not in ['None', '', None]) - old_p = Path(f'logs/{character}_persistent.json') - p = Path(f'logs/persistent_{character}.json') - if should_load_history and old_p.exists(): - logger.warning(f"Renaming {old_p} to {p}") - old_p.rename(p) - - if should_load_history and p.exists(): - f = json.loads(open(p, 'rb').read()) - if 'internal' in f and 'visible' in f: - history = f - else: - history = {'internal': [], 'visible': []} - history['internal'] = f['data'] - history['visible'] = f['data_visible'] - else: - history = {'internal': [], 'visible': []} - if greeting != "": - history['internal'] += [['<|BEGIN-VISIBLE-CHAT|>', greeting]] - history['visible'] += [['', apply_extensions('output', greeting, state, is_chat=True)]] - - return history +def delete_history(unique_id, character, mode): + p = get_history_file_path(unique_id, character, mode) + delete_file(p) def replace_character_names(text, name1, name2): @@ -465,61 +529,55 @@ def load_character(character, name1, name2, instruct=False): greeting_field = 'greeting' picture = None - # Delete the profile picture cache, if any - if Path("cache/pfp_character.png").exists() and not instruct: - Path("cache/pfp_character.png").unlink() - if instruct: name1 = name2 = '' folder = 'instruction-templates' else: folder = 'characters' - if character not in ['None', '', None]: - picture = generate_pfp_cache(character) - filepath = None - for extension in ["yml", "yaml", "json"]: - filepath = Path(f'{folder}/{character}.{extension}') - if filepath.exists(): - break + filepath = None + for extension in ["yml", "yaml", "json"]: + filepath = Path(f'{folder}/{character}.{extension}') + if filepath.exists(): + break - if filepath is None: - logger.error(f"Could not find character file for {character} in {folder} folder. Please check your spelling.") - return name1, name2, picture, greeting, context, turn_template.replace("\n", r"\n") + if filepath is None or not filepath.exists(): + logger.error(f"Could not find the character \"{character}\" inside {folder}/. No character has been loaded.") + raise ValueError - file_contents = open(filepath, 'r', encoding='utf-8').read() - data = json.loads(file_contents) if extension == "json" else yaml.safe_load(file_contents) + file_contents = open(filepath, 'r', encoding='utf-8').read() + data = json.loads(file_contents) if extension == "json" else yaml.safe_load(file_contents) - # Finding the bot's name - for k in ['name', 'bot', '<|bot|>', 'char_name']: - if k in data and data[k] != '': - name2 = data[k] - break + if Path("cache/pfp_character.png").exists() and not instruct: + Path("cache/pfp_character.png").unlink() - # Find the user name (if any) - for k in ['your_name', 'user', '<|user|>']: - if k in data and data[k] != '': - name1 = data[k] - break + picture = generate_pfp_cache(character) - if 'context' in data: - context = data['context'] - if not instruct: - context = context.strip() + '\n' - elif "char_persona" in data: - context = build_pygmalion_style_context(data) - greeting_field = 'char_greeting' + # Finding the bot's name + for k in ['name', 'bot', '<|bot|>', 'char_name']: + if k in data and data[k] != '': + name2 = data[k] + break - if greeting_field in data: - greeting = data[greeting_field] + # Find the user name (if any) + for k in ['your_name', 'user', '<|user|>']: + if k in data and data[k] != '': + name1 = data[k] + break - if 'turn_template' in data: - turn_template = data['turn_template'] + if 'context' in data: + context = data['context'] + if not instruct: + context = context.strip() + '\n' + elif "char_persona" in data: + context = build_pygmalion_style_context(data) + greeting_field = 'char_greeting' - else: - context = shared.settings['context'] - name2 = shared.settings['name2'] - greeting = shared.settings['greeting'] + if greeting_field in data: + greeting = data[greeting_field] + + if 'turn_template' in data: + turn_template = data['turn_template'] return name1, name2, picture, greeting, context, turn_template.replace("\n", r"\n") diff --git a/modules/shared.py b/modules/shared.py index 2c562d2b..e534af20 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -24,7 +24,6 @@ processing_message = '*Is typing...*' gradio = {} persistent_interface_state = {} need_restart = False -session_is_loading = False # UI defaults settings = { @@ -33,7 +32,6 @@ settings = { 'start_with': '', 'mode': 'chat', 'chat_style': 'cai-chat', - 'character': 'None', 'prompt-default': 'QA', 'prompt-notebook': 'QA', 'preset': 'simple-1', @@ -54,9 +52,7 @@ settings = { 'skip_special_tokens': True, 'stream': True, 'name1': 'You', - 'name2': 'Assistant', - 'context': 'This is a conversation with your Assistant. It is a computer program designed to help you with various tasks such as answering questions, providing recommendations, and helping with decision making. You can ask it anything you want and it will do its best to give you accurate and relevant information.', - 'greeting': '', + 'character': 'Assistant', 'instruction_template': 'Alpaca', 'chat-instruct_command': 'Continue the chat dialogue below. Write a single reply for the character "<|character|>".\n\n<|prompt|>', 'autoload_model': False, diff --git a/modules/ui_chat.py b/modules/ui_chat.py index a3f56337..1e091c7d 100644 --- a/modules/ui_chat.py +++ b/modules/ui_chat.py @@ -12,7 +12,7 @@ from modules.utils import gradio inputs = ('Chat input', 'interface_state') reload_arr = ('history', 'name1', 'name2', 'mode', 'chat_style') -clear_arr = ('Clear history-confirm', 'Clear history', 'Clear history-cancel') +clear_arr = ('delete_chat-confirm', 'delete_chat', 'delete_chat-cancel') def create_ui(): @@ -23,7 +23,7 @@ def create_ui(): with gr.Tab('Chat', elem_id='chat-tab', elem_classes=("old-ui" if shared.args.chat_buttons else None)): with gr.Row(): with gr.Column(elem_id='chat-col'): - shared.gradio['display'] = gr.HTML(value=chat_html_wrapper({'internal': [], 'visible': []}, shared.settings['name1'], shared.settings['name2'], 'chat', 'cai-chat')) + shared.gradio['display'] = gr.HTML(value=chat_html_wrapper({'internal': [], 'visible': []}, '', '', 'chat', 'cai-chat')) with gr.Row(elem_id="chat-input-row"): with gr.Column(scale=1, elem_id='gr-hover-container'): @@ -45,26 +45,34 @@ def create_ui(): shared.gradio['Regenerate'] = gr.Button('Regenerate (Ctrl + Enter)', elem_id='Regenerate') shared.gradio['Continue'] = gr.Button('Continue (Alt + Enter)', elem_id='Continue') shared.gradio['Remove last'] = gr.Button('Remove last reply (Ctrl + Shift + Backspace)', elem_id='Remove-last') + with gr.Row(): shared.gradio['Replace last reply'] = gr.Button('Replace last reply (Ctrl + Shift + L)', elem_id='Replace-last') shared.gradio['Copy last reply'] = gr.Button('Copy last reply (Ctrl + Shift + K)', elem_id='Copy-last') shared.gradio['Impersonate'] = gr.Button('Impersonate (Ctrl + Shift + M)', elem_id='Impersonate') + with gr.Row(): shared.gradio['Send dummy message'] = gr.Button('Send dummy message') shared.gradio['Send dummy reply'] = gr.Button('Send dummy reply') + with gr.Row(): - shared.gradio['Clear history'] = gr.Button('Clear history') - shared.gradio['Clear history-cancel'] = gr.Button('Cancel', visible=False) - shared.gradio['Clear history-confirm'] = gr.Button('Confirm', variant='stop', visible=False, elem_id='clear-history-confirm') + shared.gradio['Start new chat'] = gr.Button('Start new chat') + with gr.Row(): shared.gradio['send-chat-to-default'] = gr.Button('Send to default') shared.gradio['send-chat-to-notebook'] = gr.Button('Send to notebook') + with gr.Row(): + shared.gradio['unique_id'] = gr.Dropdown(label='Past chats', elem_classes=['slim-dropdown']) + shared.gradio['delete_chat'] = gr.Button('🗑️', elem_classes='refresh-button') + shared.gradio['delete_chat-cancel'] = gr.Button('Cancel', visible=False, elem_classes='refresh-button') + shared.gradio['delete_chat-confirm'] = gr.Button('Confirm', variant='stop', visible=False, elem_classes='refresh-button') + with gr.Row(): shared.gradio['start_with'] = gr.Textbox(label='Start reply with', placeholder='Sure thing!', value=shared.settings['start_with']) with gr.Row(): - shared.gradio['mode'] = gr.Radio(choices=['chat', 'chat-instruct', 'instruct'], value=shared.settings['mode'] if shared.settings['mode'] in ['chat', 'instruct', 'chat-instruct'] else 'chat', label='Mode', info='Defines how the chat prompt is generated. In instruct and chat-instruct modes, the instruction template selected under Parameters > Instruction template must match the current model.', elem_id='chat-mode') + shared.gradio['mode'] = gr.Radio(choices=['chat', 'chat-instruct', 'instruct'], value='chat', label='Mode', info='Defines how the chat prompt is generated. In instruct and chat-instruct modes, the instruction template selected under Parameters > Instruction template must match the current model.', elem_id='chat-mode') shared.gradio['chat_style'] = gr.Dropdown(choices=utils.get_available_chat_styles(), label='Chat style', value=shared.settings['chat_style'], visible=shared.settings['mode'] != 'instruct') @@ -73,15 +81,15 @@ def create_chat_settings_ui(): with gr.Row(): with gr.Column(scale=8): with gr.Row(): - shared.gradio['character_menu'] = gr.Dropdown(value='None', choices=utils.get_available_characters(), label='Character', elem_id='character-menu', info='Used in chat and chat-instruct modes.', elem_classes='slim-dropdown') + shared.gradio['character_menu'] = gr.Dropdown(value='', choices=utils.get_available_characters(), label='Character', elem_id='character-menu', info='Used in chat and chat-instruct modes.', elem_classes='slim-dropdown') ui.create_refresh_button(shared.gradio['character_menu'], lambda: None, lambda: {'choices': utils.get_available_characters()}, 'refresh-button') shared.gradio['save_character'] = gr.Button('💾', elem_classes='refresh-button') shared.gradio['delete_character'] = gr.Button('🗑️', elem_classes='refresh-button') shared.gradio['name1'] = gr.Textbox(value=shared.settings['name1'], lines=1, label='Your name') - shared.gradio['name2'] = gr.Textbox(value=shared.settings['name2'], lines=1, label='Character\'s name') - shared.gradio['context'] = gr.Textbox(value=shared.settings['context'], lines=10, label='Context', elem_classes=['add_scrollbar']) - shared.gradio['greeting'] = gr.Textbox(value=shared.settings['greeting'], lines=5, label='Greeting', elem_classes=['add_scrollbar']) + shared.gradio['name2'] = gr.Textbox(value='', lines=1, label='Character\'s name') + shared.gradio['context'] = gr.Textbox(value='', lines=10, label='Context', elem_classes=['add_scrollbar']) + shared.gradio['greeting'] = gr.Textbox(value='', lines=5, label='Greeting', elem_classes=['add_scrollbar']) with gr.Column(scale=1): shared.gradio['character_picture'] = gr.Image(label='Character picture', type='pil') @@ -146,7 +154,7 @@ def create_event_handlers(): lambda x: (x, ''), gradio('textbox'), gradio('Chat input', 'textbox'), show_progress=False).then( chat.generate_chat_reply_wrapper, gradio(inputs), gradio('display', 'history'), show_progress=False).then( ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( - chat.save_persistent_history, gradio('history', 'character_menu', 'mode'), None).then( + chat.save_history, gradio('history', 'unique_id', 'character_menu', 'mode'), None).then( lambda: None, None, None, _js=f'() => {{{ui.audio_notification_js}}}') shared.gradio['textbox'].submit( @@ -154,21 +162,21 @@ def create_event_handlers(): lambda x: (x, ''), gradio('textbox'), gradio('Chat input', 'textbox'), show_progress=False).then( chat.generate_chat_reply_wrapper, gradio(inputs), gradio('display', 'history'), show_progress=False).then( ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( - chat.save_persistent_history, gradio('history', 'character_menu', 'mode'), None).then( + chat.save_history, gradio('history', 'unique_id', 'character_menu', 'mode'), None).then( lambda: None, None, None, _js=f'() => {{{ui.audio_notification_js}}}') shared.gradio['Regenerate'].click( ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( partial(chat.generate_chat_reply_wrapper, regenerate=True), gradio(inputs), gradio('display', 'history'), show_progress=False).then( ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( - chat.save_persistent_history, gradio('history', 'character_menu', 'mode'), None).then( + chat.save_history, gradio('history', 'unique_id', 'character_menu', 'mode'), None).then( lambda: None, None, None, _js=f'() => {{{ui.audio_notification_js}}}') shared.gradio['Continue'].click( ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( partial(chat.generate_chat_reply_wrapper, _continue=True), gradio(inputs), gradio('display', 'history'), show_progress=False).then( ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( - chat.save_persistent_history, gradio('history', 'character_menu', 'mode'), None).then( + chat.save_history, gradio('history', 'unique_id', 'character_menu', 'mode'), None).then( lambda: None, None, None, _js=f'() => {{{ui.audio_notification_js}}}') shared.gradio['Impersonate'].click( @@ -183,60 +191,81 @@ def create_event_handlers(): chat.replace_last_reply, gradio('textbox', 'interface_state'), gradio('history')).then( lambda: '', None, gradio('textbox'), show_progress=False).then( chat.redraw_html, gradio(reload_arr), gradio('display')).then( - chat.save_persistent_history, gradio('history', 'character_menu', 'mode'), None) + chat.save_history, gradio('history', 'unique_id', 'character_menu', 'mode'), None) shared.gradio['Send dummy message'].click( ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( chat.send_dummy_message, gradio('textbox', 'interface_state'), gradio('history')).then( lambda: '', None, gradio('textbox'), show_progress=False).then( chat.redraw_html, gradio(reload_arr), gradio('display')).then( - chat.save_persistent_history, gradio('history', 'character_menu', 'mode'), None) + chat.save_history, gradio('history', 'unique_id', 'character_menu', 'mode'), None) shared.gradio['Send dummy reply'].click( ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( chat.send_dummy_reply, gradio('textbox', 'interface_state'), gradio('history')).then( lambda: '', None, gradio('textbox'), show_progress=False).then( chat.redraw_html, gradio(reload_arr), gradio('display')).then( - chat.save_persistent_history, gradio('history', 'character_menu', 'mode'), None) - - shared.gradio['Clear history'].click(lambda: [gr.update(visible=True), gr.update(visible=False), gr.update(visible=True)], None, gradio(clear_arr)) - shared.gradio['Clear history-cancel'].click(lambda: [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)], None, gradio(clear_arr)) - shared.gradio['Clear history-confirm'].click( - ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( - lambda: [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)], None, gradio(clear_arr)).then( - chat.clear_chat_log, gradio('interface_state'), gradio('history')).then( - chat.redraw_html, gradio(reload_arr), gradio('display')).then( - chat.save_persistent_history, gradio('history', 'character_menu', 'mode'), None) + chat.save_history, gradio('history', 'unique_id', 'character_menu', 'mode'), None) shared.gradio['Remove last'].click( ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( chat.remove_last_message, gradio('history'), gradio('textbox', 'history'), show_progress=False).then( chat.redraw_html, gradio(reload_arr), gradio('display')).then( - chat.save_persistent_history, gradio('history', 'character_menu', 'mode'), None) - - shared.gradio['character_menu'].change( - partial(chat.load_character, instruct=False), gradio('character_menu', 'name1', 'name2'), gradio('name1', 'name2', 'character_picture', 'greeting', 'context', 'dummy')).then( - ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( - chat.load_persistent_history, gradio('interface_state'), gradio('history')).then( - chat.redraw_html, gradio(reload_arr), gradio('display')) + chat.save_history, gradio('history', 'unique_id', 'character_menu', 'mode'), None) shared.gradio['Stop'].click( stop_everything_event, None, None, queue=False).then( chat.redraw_html, gradio(reload_arr), gradio('display')) + if not shared.args.multi_user: + shared.gradio['unique_id'].select( + chat.load_history, gradio('unique_id', 'character_menu', 'mode'), gradio('history')).then( + chat.redraw_html, gradio(reload_arr), gradio('display')) + + shared.gradio['Start new chat'].click( + 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')) + + 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)) + shared.gradio['delete_chat-confirm'].click( + ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( + chat.delete_history, gradio('unique_id', 'character_menu', 'mode'), None).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: [gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)], None, gradio(clear_arr)) + + 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( + chat.save_history, gradio('history', 'unique_id', 'character_menu', 'mode'), None).then( + lambda: None, None, None, _js=f'() => {{{ui.switch_tabs_js}; switch_to_chat()}}') + + shared.gradio['character_menu'].change( + partial(chat.load_character, instruct=False), gradio('character_menu', 'name1', 'name2'), gradio('name1', 'name2', 'character_picture', 'greeting', 'context', 'dummy')).success( + 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')) + shared.gradio['mode'].change( lambda x: gr.update(visible=x != 'instruct'), gradio('mode'), gradio('chat_style'), show_progress=False).then( - chat.redraw_html, gradio(reload_arr), gradio('display')) + ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( + partial(chat.character_is_loaded, raise_exception=True), gradio('interface_state'), None).success( + 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')) shared.gradio['chat_style'].change(chat.redraw_html, gradio(reload_arr), gradio('display')) shared.gradio['instruction_template'].change( partial(chat.load_character, instruct=True), gradio('instruction_template', 'name1_instruct', 'name2_instruct'), gradio('name1_instruct', 'name2_instruct', 'dummy', 'dummy', 'context_instruct', 'turn_template')) - shared.gradio['load_chat_history'].upload( - chat.load_history, gradio('load_chat_history', 'history'), gradio('history')).then( - chat.redraw_html, gradio(reload_arr), gradio('display')).then( - lambda: None, None, None, _js=f'() => {{{ui.switch_tabs_js}; switch_to_chat()}}') - shared.gradio['Copy last reply'].click(chat.send_last_reply_to_input, gradio('history'), gradio('textbox'), show_progress=False) # Save/delete a character diff --git a/modules/ui_file_saving.py b/modules/ui_file_saving.py index 30886e5b..9febd296 100644 --- a/modules/ui_file_saving.py +++ b/modules/ui_file_saving.py @@ -1,9 +1,6 @@ -import copy -import json - import gradio as gr -from modules import chat, presets, shared, ui, ui_chat, utils +from modules import chat, presets, shared, ui, utils from modules.utils import gradio @@ -76,35 +73,3 @@ def create_event_handlers(): lambda x: f'{x}.yaml', gradio('preset_menu'), gradio('delete_filename')).then( lambda: 'presets/', None, gradio('delete_root')).then( lambda: gr.update(visible=True), None, gradio('file_deleter')) - - if not shared.args.multi_user: - shared.gradio['save_session'].click( - ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( - save_session, gradio('interface_state'), gradio('temporary_text')).then( - None, gradio('temporary_text'), None, _js=f"(contents) => {{{ui.save_files_js}; saveSession(contents)}}") - - shared.gradio['load_session'].upload( - ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( - load_session, gradio('load_session', 'interface_state'), gradio('interface_state')).then( - ui.apply_interface_values, gradio('interface_state'), gradio(ui.list_interface_input_elements()), show_progress=False).then( - chat.redraw_html, gradio(ui_chat.reload_arr), gradio('display')).then( - None, None, None, _js='() => {alert("The session has been loaded.")}') - - -def load_session(file, state): - decoded_file = file if isinstance(file, str) else file.decode('utf-8') - data = json.loads(decoded_file) - - if 'character_menu' in data and state.get('character_menu') != data.get('character_menu'): - shared.session_is_loading = True - - state.update(data) - return state - - -def save_session(state): - output = copy.deepcopy(state) - for key in ['prompt_menu-default', 'prompt_menu-notebook']: - del output[key] - - return json.dumps(output, indent=4) diff --git a/modules/ui_session.py b/modules/ui_session.py index 537a31f2..53d9ec3f 100644 --- a/modules/ui_session.py +++ b/modules/ui_session.py @@ -22,10 +22,6 @@ def create_ui(): shared.gradio['bool_menu'] = gr.CheckboxGroup(choices=get_boolean_arguments(), value=get_boolean_arguments(active=True), label="Boolean command-line flags", elem_classes='checkboxgroup-table') with gr.Column(): - if not shared.args.multi_user: - shared.gradio['save_session'] = gr.Button('Save session') - shared.gradio['load_session'] = gr.File(type='binary', file_types=['.json'], label="Upload Session JSON") - extension_name = gr.Textbox(lines=1, label='Install or update an extension', info='Enter the GitHub URL below and press Enter. For a list of extensions, see: https://github.com/oobabooga/text-generation-webui-extensions ⚠️ WARNING ⚠️ : extensions can execute arbitrary code. Make sure to inspect their source code before activating them.') extension_status = gr.Markdown() diff --git a/modules/utils.py b/modules/utils.py index 0a7edffa..f60597a6 100644 --- a/modules/utils.py +++ b/modules/utils.py @@ -94,7 +94,7 @@ def get_available_prompts(): def get_available_characters(): paths = (x for x in Path('characters').iterdir() if x.suffix in ('.json', '.yaml', '.yml')) - return ['None'] + sorted(set((k.stem for k in paths)), key=natural_keys) + return sorted(set((k.stem for k in paths)), key=natural_keys) def get_available_instruction_templates(): diff --git a/settings-template.yaml b/settings-template.yaml index 66d98d39..0696f503 100644 --- a/settings-template.yaml +++ b/settings-template.yaml @@ -3,7 +3,6 @@ show_controls: true start_with: '' mode: chat chat_style: cai-chat -character: None prompt-default: QA prompt-notebook: QA preset: simple-1 @@ -24,9 +23,7 @@ add_bos_token: true skip_special_tokens: true stream: true name1: You -name2: Assistant -context: This is a conversation with your Assistant. It is a computer program designed to help you with various tasks such as answering questions, providing recommendations, and helping with decision making. You can ask it anything you want and it will do its best to give you accurate and relevant information. -greeting: '' +character: Assistant instruction_template: Alpaca chat-instruct_command: |- Continue the chat dialogue below. Write a single reply for the character "<|character|>".