diff --git a/css/main.css b/css/main.css index 4daecd3c..6911ab11 100644 --- a/css/main.css +++ b/css/main.css @@ -82,7 +82,7 @@ div.svelte-15lo0d8 > *, div.svelte-15lo0d8 > .form > * { } .textbox_default textarea { - height: calc(100vh - 381px); + height: calc(100vh - 416px); } .textbox_default_output textarea { @@ -113,4 +113,19 @@ button { .small-button { max-width: 171px; +} + +.file-saver { + position: fixed !important; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); /* center horizontally */ + max-width: 500px; + background-color: var(--input-background-fill); + border: 2px solid black !important; + z-index: 1000; +} + +.dark .file-saver { + border: 2px solid white !important; } \ No newline at end of file diff --git a/modules/chat.py b/modules/chat.py index 74ab6bc4..f4acd0cd 100644 --- a/modules/chat.py +++ b/modules/chat.py @@ -17,7 +17,7 @@ from modules.html_generator import chat_html_wrapper, make_thumbnail from modules.logging_colors import logger from modules.text_generation import (generate_reply, get_encoded_length, get_max_prompt_length) -from modules.utils import replace_all +from modules.utils import delete_file, replace_all, save_file def get_turn_substrings(state, instruct=False): @@ -320,8 +320,8 @@ def generate_chat_reply(text, history, state, regenerate=False, _continue=False, # Same as above but returns HTML for the UI def generate_chat_reply_wrapper(text, start_with, state, regenerate=False, _continue=False): - if start_with != '' and _continue == False: - if regenerate == True: + if start_with != '' and not _continue: + if regenerate: text = remove_last_message() regenerate = False @@ -628,18 +628,7 @@ def upload_your_profile_picture(img): logger.info('Profile picture saved to "cache/pfp_me.png"') -def delete_file(path): - if path.exists(): - logger.warning(f'Deleting {path}') - path.unlink(missing_ok=True) - - -def save_character(name, greeting, context, picture, filename, instruct=False): - if filename == "": - logger.error("The filename is empty, so the character will not be saved.") - return - - folder = 'characters' if not instruct else 'characters/instruction-following' +def generate_character_yaml(name, greeting, context): data = { 'name': name, 'greeting': greeting, @@ -647,22 +636,37 @@ def save_character(name, greeting, context, picture, filename, instruct=False): } data = {k: v for k, v in data.items() if v} # Strip falsy - filepath = Path(f'{folder}/{filename}.yaml') - with filepath.open('w') as f: - yaml.dump(data, f, sort_keys=False) + return yaml.dump(data, sort_keys=False) - logger.info(f'Wrote {filepath}') - path_to_img = Path(f'{folder}/{filename}.png') - if picture and not instruct: + +def generate_instruction_template_yaml(user, bot, context, turn_template): + data = { + 'user': user, + 'bot': bot, + 'turn_template': turn_template, + 'context': context, + } + + data = {k: v for k, v in data.items() if v} # Strip falsy + return yaml.dump(data, sort_keys=False) + + +def save_character(name, greeting, context, picture, filename): + if filename == "": + logger.error("The filename is empty, so the character will not be saved.") + return + + data = generate_character_yaml(name, greeting, context) + filepath = Path(f'characters/{filename}.yaml') + save_file(filepath, data) + path_to_img = Path(f'characters/{filename}.png') + if picture is not None: picture.save(path_to_img) - logger.info(f'Wrote {path_to_img}') - elif path_to_img.exists(): - delete_file(path_to_img) + logger.info(f'Saved {path_to_img}.') def delete_character(name, instruct=False): - folder = 'characters' if not instruct else 'characters/instruction-following' for extension in ["yml", "yaml", "json"]: - delete_file(Path(f'{folder}/{name}.{extension}')) + delete_file(Path(f'characters/{name}.{extension}')) - delete_file(Path(f'{folder}/{name}.png')) + delete_file(Path(f'characters/{name}.png')) diff --git a/modules/logging_colors.py b/modules/logging_colors.py index 80cb2d1d..a0c97c3a 100644 --- a/modules/logging_colors.py +++ b/modules/logging_colors.py @@ -3,7 +3,10 @@ import logging import platform -logging.basicConfig(format='%(levelname)s:%(message)s') +logging.basicConfig( + format='%(asctime)s %(levelname)s:%(message)s', + datefmt='%Y-%m-%d %H:%M:%S', +) def add_coloring_to_emit_windows(fn): diff --git a/modules/utils.py b/modules/utils.py index 4fa9f868..2fe72525 100644 --- a/modules/utils.py +++ b/modules/utils.py @@ -3,6 +3,42 @@ import re from pathlib import Path from modules import shared +from modules.logging_colors import logger + + +def save_file(fname, contents): + if fname == '': + logger.error('File name is empty!') + return + + root_folder = Path(__file__).resolve().parent.parent + abs_path = Path(fname).resolve() + rel_path = abs_path.relative_to(root_folder) + if rel_path.parts[0] == '..': + logger.error(f'Invalid file path: {fname}') + return + + with open(abs_path, 'w', encoding='utf-8') as f: + f.write(contents) + + logger.info(f'Saved {abs_path}.') + + +def delete_file(fname): + if fname == '': + logger.error('File name is empty!') + return + + root_folder = Path(__file__).resolve().parent.parent + abs_path = Path(fname).resolve() + rel_path = abs_path.relative_to(root_folder) + if rel_path.parts[0] == '..': + logger.error(f'Invalid file path: {fname}') + return + + if abs_path.exists(): + abs_path.unlink() + logger.info(f'Deleted {fname}.') def atoi(text): diff --git a/server.py b/server.py index a507cf77..c56e1bcb 100644 --- a/server.py +++ b/server.py @@ -117,21 +117,13 @@ def load_preset_values(preset_menu, state, return_dict=False): return state, *[generate_params[k] for k in ['do_sample', 'temperature', 'top_p', 'typical_p', 'epsilon_cutoff', 'eta_cutoff', 'repetition_penalty', 'encoder_repetition_penalty', 'top_k', 'min_length', 'no_repeat_ngram_size', 'num_beams', 'penalty_alpha', 'length_penalty', 'early_stopping', 'mirostat_mode', 'mirostat_tau', 'mirostat_eta', 'tfs', 'top_a']] -def open_save_prompt(): - fname = f"{datetime.now().strftime('%Y-%m-%d-%H%M%S')}" - return gr.update(value=fname, visible=True), gr.update(visible=False), gr.update(visible=True) +def generate_preset_yaml(state): + data = {k: state[k] for k in ['do_sample', 'temperature', 'top_p', 'typical_p', 'epsilon_cutoff', 'eta_cutoff', 'repetition_penalty', 'encoder_repetition_penalty', 'top_k', 'min_length', 'no_repeat_ngram_size', 'num_beams', 'penalty_alpha', 'length_penalty', 'early_stopping', 'mirostat_mode', 'mirostat_tau', 'mirostat_eta', 'tfs', 'top_a']} + return yaml.dump(data, sort_keys=False) -def save_prompt(text, fname): - if fname != "": - with open(Path(f'prompts/{fname}.txt'), 'w', encoding='utf-8') as f: - f.write(text) - - message = f"Saved to prompts/{fname}.txt" - else: - message = "Error: No prompt name given." - - return message, gr.update(visible=False), gr.update(visible=True), gr.update(visible=False) +def current_time(): + return f"{datetime.now().strftime('%Y-%m-%d-%H%M%S')}" def load_prompt(fname): @@ -163,8 +155,11 @@ def load_prompt(fname): def count_tokens(text): - tokens = get_encoded_length(text) - return f'{tokens} tokens in the input.' + try: + tokens = get_encoded_length(text) + return f'{tokens} tokens in the input.' + except: + return 'Couldn\'t count the number of tokens. Is a tokenizer loaded?' def download_model_wrapper(repo_id): @@ -462,19 +457,17 @@ def create_settings_menus(default_preset): with gr.Row(): with gr.Column(): with gr.Row(): - with gr.Column(): - with gr.Row(): - shared.gradio['preset_menu'] = gr.Dropdown(choices=utils.get_available_presets(), value=default_preset if not shared.args.flexgen else 'Naive', label='Generation parameters preset') - ui.create_refresh_button(shared.gradio['preset_menu'], lambda: None, lambda: {'choices': utils.get_available_presets()}, 'refresh-button') - - with gr.Column(): - shared.gradio['seed'] = gr.Number(value=shared.settings['seed'], label='Seed (-1 for random)') + shared.gradio['preset_menu'] = gr.Dropdown(choices=utils.get_available_presets(), value=default_preset if not shared.args.flexgen else 'Naive', label='Generation parameters preset') + ui.create_refresh_button(shared.gradio['preset_menu'], lambda: None, lambda: {'choices': utils.get_available_presets()}, 'refresh-button') + with gr.Column(scale=0): + shared.gradio['save_preset'] = gr.Button('Save preset') + shared.gradio['delete_preset'] = gr.Button('Delete preset') + shared.gradio['seed'] = gr.Number(value=shared.settings['seed'], label='Seed (-1 for random)') with gr.Box(): gr.Markdown('Main parameters') with gr.Row(): with gr.Column(): - shared.gradio['do_sample'] = gr.Checkbox(value=generate_params['do_sample'], label='do_sample') shared.gradio['temperature'] = gr.Slider(0.01, 1.99, value=generate_params['temperature'], step=0.01, label='temperature', info='Primary factor to control randomness of outputs. 0 = deterministic (only the most likely token is used). Higher value = more randomness.') shared.gradio['top_p'] = gr.Slider(0.0, 1.0, value=generate_params['top_p'], step=0.01, label='top_p', info='If not set to 1, select tokens with probabilities adding up to less than this number. Higher value = higher range of possible random results.') shared.gradio['top_k'] = gr.Slider(0, 200, value=generate_params['top_k'], step=1, label='top_k', info='Similar to top_p, but select instead only the top_k most likely tokens. Higher value = higher range of possible random results.') @@ -489,6 +482,9 @@ def create_settings_menus(default_preset): shared.gradio['min_length'] = gr.Slider(0, 2000, step=1, value=generate_params['min_length'], label='min_length', info='Minimum generation length in tokens.') shared.gradio['tfs'] = gr.Slider(0.0, 1.0, value=generate_params['tfs'], step=0.01, label='tfs') shared.gradio['top_a'] = gr.Slider(0.0, 1.0, value=generate_params['top_a'], step=0.01, label='top_a') + shared.gradio['do_sample'] = gr.Checkbox(value=generate_params['do_sample'], label='do_sample') + + gr.Markdown('[Click here for more information.](https://github.com/oobabooga/text-generation-webui/blob/main/docs/Generation-parameters.md)') with gr.Column(): create_chat_settings_menus() @@ -521,11 +517,66 @@ def create_settings_menus(default_preset): shared.gradio['skip_special_tokens'] = gr.Checkbox(value=shared.settings['skip_special_tokens'], label='Skip special tokens', info='Some specific models need this unset.') shared.gradio['stream'] = gr.Checkbox(value=not shared.args.no_stream, label='Activate text streaming') - gr.Markdown('[Click here for more information.](https://github.com/oobabooga/text-generation-webui/blob/main/docs/Generation-parameters.md)') - shared.gradio['preset_menu'].change(load_preset_values, [shared.gradio[k] for k in ['preset_menu', 'interface_state']], [shared.gradio[k] for k in ['interface_state', 'do_sample', 'temperature', 'top_p', 'typical_p', 'epsilon_cutoff', 'eta_cutoff', 'repetition_penalty', 'encoder_repetition_penalty', 'top_k', 'min_length', 'no_repeat_ngram_size', 'num_beams', 'penalty_alpha', 'length_penalty', 'early_stopping', 'mirostat_mode', 'mirostat_tau', 'mirostat_eta', 'tfs', 'top_a']]) +def create_file_saving_menus(): + + # Text file saver + with gr.Box(visible=False, elem_classes='file-saver') as shared.gradio['file_saver']: + shared.gradio['save_filename'] = gr.Textbox(lines=1, label='File name') + shared.gradio['save_root'] = gr.Textbox(lines=1, label='File folder', info='For reference. Unchangeable.', interactive=False) + shared.gradio['save_contents'] = gr.Textbox(lines=10, label='File contents') + with gr.Row(): + shared.gradio['save_confirm'] = gr.Button('Save', elem_classes="small-button") + shared.gradio['save_cancel'] = gr.Button('Cancel', elem_classes="small-button") + + # Text file deleter + with gr.Box(visible=False, elem_classes='file-saver') as shared.gradio['file_deleter']: + shared.gradio['delete_filename'] = gr.Textbox(lines=1, label='File name') + shared.gradio['delete_root'] = gr.Textbox(lines=1, label='File folder', info='For reference. Unchangeable.', interactive=False) + with gr.Row(): + shared.gradio['delete_confirm'] = gr.Button('Delete', elem_classes="small-button", variant='stop') + shared.gradio['delete_cancel'] = gr.Button('Cancel', elem_classes="small-button") + + shared.gradio['save_confirm'].click( + lambda x, y, z: utils.save_file(x + y, z), [shared.gradio[k] for k in ['save_root', 'save_filename', 'save_contents']], None).then( + lambda: gr.update(visible=False), None, shared.gradio['file_saver']) + + shared.gradio['delete_confirm'].click( + lambda x, y: utils.delete_file(x + y), [shared.gradio[k] for k in ['delete_root', 'delete_filename']], None).then( + lambda: gr.update(visible=False), None, shared.gradio['file_deleter']) + + shared.gradio['delete_cancel'].click(lambda: gr.update(visible=False), None, shared.gradio['file_deleter']) + shared.gradio['save_cancel'].click(lambda: gr.update(visible=False), None, shared.gradio['file_saver']) + + # Character saver/deleter + if shared.is_chat(): + with gr.Box(visible=False, elem_classes='file-saver') as shared.gradio['character_saver']: + shared.gradio['save_character_filename'] = gr.Textbox(lines=1, label='File name', info='The character will be saved to your characters/ folder with this base filename.') + with gr.Row(): + shared.gradio['save_character_confirm'] = gr.Button('Save', elem_classes="small-button") + shared.gradio['save_character_cancel'] = gr.Button('Cancel', elem_classes="small-button") + + with gr.Box(visible=False, elem_classes='file-saver') as shared.gradio['character_deleter']: + gr.Markdown('Confirm the character deletion?') + with gr.Row(): + shared.gradio['delete_character_confirm'] = gr.Button('Delete', elem_classes="small-button", variant='stop') + shared.gradio['delete_character_cancel'] = gr.Button('Cancel', elem_classes="small-button") + + shared.gradio['save_character_confirm'].click( + chat.save_character, [shared.gradio[k] for k in ['name2', 'greeting', 'context', 'character_picture', 'save_character_filename']], None).then( + lambda: gr.update(visible=False), None, shared.gradio['character_saver']) + + shared.gradio['delete_character_confirm'].click( + chat.delete_character, shared.gradio['character_menu'], None).then( + lambda: gr.update(visible=False), None, shared.gradio['character_deleter']).then( + lambda: gr.update(choices=utils.get_available_characters()), outputs=shared.gradio['character_menu']) + + shared.gradio['save_character_cancel'].click(lambda: gr.update(visible=False), None, shared.gradio['character_saver']) + shared.gradio['delete_character_cancel'].click(lambda: gr.update(visible=False), None, shared.gradio['character_deleter']) + + def set_interface_arguments(interface_mode, extensions, bool_active): modes = ["default", "notebook", "chat", "cai_chat"] cmd_list = vars(shared.args) @@ -626,14 +677,9 @@ def create_interface(): with gr.Row(): shared.gradio['character_menu'] = gr.Dropdown(choices=utils.get_available_characters(), label='Character', elem_id='character-menu', info='Used in chat and chat-instruct modes.') ui.create_refresh_button(shared.gradio['character_menu'], lambda: None, lambda: {'choices': utils.get_available_characters()}, 'refresh-button') - shared.gradio['save_character'] = ui.create_save_button(elem_id='refresh-button') - shared.gradio['delete_character'] = ui.create_delete_button(elem_id='refresh-button') - - shared.gradio['save_character-filename'] = gr.Textbox(lines=1, label='File name:', interactive=True, visible=False) - shared.gradio['save_character-confirm'] = gr.Button('Confirm save character', elem_classes="small-button", variant='primary', visible=False) - shared.gradio['save_character-cancel'] = gr.Button('Cancel', elem_classes="small-button", visible=False) - shared.gradio['delete_character-confirm'] = gr.Button('Confirm delete character', elem_classes="small-button", variant='stop', visible=False) - shared.gradio['delete_character-cancel'] = gr.Button('Cancel', elem_classes="small-button", visible=False) + with gr.Column(scale=0): + shared.gradio['save_character'] = gr.Button('Save character') + shared.gradio['delete_character'] = gr.Button('Delete character') 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') @@ -647,6 +693,9 @@ def create_interface(): with gr.Row(): shared.gradio['instruction_template'] = gr.Dropdown(choices=utils.get_available_instruction_templates(), label='Instruction template', value='None', info='Change this according to the model/LoRA that you are using. Used in instruct and chat-instruct modes.') ui.create_refresh_button(shared.gradio['instruction_template'], lambda: None, lambda: {'choices': utils.get_available_instruction_templates()}, 'refresh-button') + with gr.Column(scale=0): + shared.gradio['save_template'] = gr.Button('Save template') + shared.gradio['delete_template'] = gr.Button('Delete template') shared.gradio['name1_instruct'] = gr.Textbox(value='', lines=2, label='User string') shared.gradio['name2_instruct'] = gr.Textbox(value='', lines=1, label='Bot string') @@ -716,9 +765,10 @@ def create_interface(): shared.gradio['prompt_menu'] = gr.Dropdown(choices=utils.get_available_prompts(), value='None', label='Prompt') ui.create_refresh_button(shared.gradio['prompt_menu'], lambda: None, lambda: {'choices': utils.get_available_prompts()}, 'refresh-button') - shared.gradio['open_save_prompt'] = gr.Button('Save prompt') - shared.gradio['save_prompt'] = gr.Button('Confirm save prompt', visible=False) - shared.gradio['prompt_to_save'] = gr.Textbox(elem_classes="textbox_default", lines=1, label='Prompt name:', interactive=True, visible=False) + with gr.Row(): + shared.gradio['save_prompt'] = gr.Button('Save prompt') + shared.gradio['delete_prompt'] = gr.Button('Delete prompt') + shared.gradio['count_tokens'] = gr.Button('Count tokens') shared.gradio['status'] = gr.Markdown('') @@ -736,22 +786,19 @@ def create_interface(): shared.gradio['textbox'] = gr.Textbox(value=default_text, elem_classes="textbox_default", lines=27, label='Input') shared.gradio['max_new_tokens'] = gr.Slider(minimum=shared.settings['max_new_tokens_min'], maximum=shared.settings['max_new_tokens_max'], step=1, label='max_new_tokens', value=shared.settings['max_new_tokens']) with gr.Row(): - shared.gradio['Generate'] = gr.Button('Generate', variant='primary', elem_classes="small-button") - shared.gradio['Stop'] = gr.Button('Stop', elem_classes="small-button") - shared.gradio['Continue'] = gr.Button('Continue', elem_classes="small-button") - shared.gradio['open_save_prompt'] = gr.Button('Save prompt', elem_classes="small-button") - shared.gradio['save_prompt'] = gr.Button('Confirm save prompt', visible=False, elem_classes="small-button") - shared.gradio['count_tokens'] = gr.Button('Count tokens', elem_classes="small-button") + shared.gradio['Generate'] = gr.Button('Generate', variant='primary') + shared.gradio['Stop'] = gr.Button('Stop') + shared.gradio['Continue'] = gr.Button('Continue') + shared.gradio['count_tokens'] = gr.Button('Count tokens') with gr.Row(): + shared.gradio['prompt_menu'] = gr.Dropdown(choices=utils.get_available_prompts(), value='None', label='Prompt') + ui.create_refresh_button(shared.gradio['prompt_menu'], lambda: None, lambda: {'choices': utils.get_available_prompts()}, 'refresh-button') with gr.Column(): - with gr.Row(): - shared.gradio['prompt_menu'] = gr.Dropdown(choices=utils.get_available_prompts(), value='None', label='Prompt') - ui.create_refresh_button(shared.gradio['prompt_menu'], lambda: None, lambda: {'choices': utils.get_available_prompts()}, 'refresh-button') + shared.gradio['save_prompt'] = gr.Button('Save prompt') + shared.gradio['delete_prompt'] = gr.Button('Delete prompt') - with gr.Column(): - shared.gradio['prompt_to_save'] = gr.Textbox(elem_classes="textbox_default", lines=1, label='Prompt name:', interactive=True, visible=False) - shared.gradio['status'] = gr.Markdown('') + shared.gradio['status'] = gr.Markdown('') with gr.Column(): with gr.Tab('Raw'): @@ -803,6 +850,9 @@ def create_interface(): shared.gradio['toggle_dark_mode'].click(lambda: None, None, None, _js='() => {document.getElementsByTagName("body")[0].classList.toggle("dark")}') + # Floating menus for saving/deleting files + create_file_saving_menus() + # chat mode event handlers if shared.is_chat(): shared.input_params = [shared.gradio[k] for k in ['Chat input', 'start_with', 'interface_state']] @@ -896,28 +946,21 @@ def create_interface(): # Save/delete a character shared.gradio['save_character'].click( - lambda x: x, shared.gradio['name2'], shared.gradio['save_character-filename'], show_progress=True).then( - lambda: [gr.update(visible=True)] * 3, None, [shared.gradio[k] for k in ['save_character-filename', 'save_character-confirm', 'save_character-cancel']], show_progress=False) + lambda x: x, shared.gradio['name2'], shared.gradio['save_character_filename']).then( + lambda: gr.update(visible=True), None, shared.gradio['character_saver']) - shared.gradio['save_character-cancel'].click( - lambda: [gr.update(visible=False)] * 3, None, [shared.gradio[k] for k in ['save_character-filename', 'save_character-confirm', 'save_character-cancel']], show_progress=False) + shared.gradio['delete_character'].click(lambda: gr.update(visible=True), None, shared.gradio['character_deleter']) - shared.gradio['save_character-confirm'].click( - partial(chat.save_character, instruct=False), [shared.gradio[k] for k in ['name2', 'greeting', 'context', 'character_picture', 'save_character-filename']], None).then( - lambda: [gr.update(visible=False)] * 3, None, [shared.gradio[k] for k in ['save_character-filename', 'save_character-confirm', 'save_character-cancel']], show_progress=False).then( - lambda x: x, shared.gradio['save_character-filename'], shared.gradio['character_menu']) + shared.gradio['save_template'].click( + lambda: 'My Template.yaml', None, shared.gradio['save_filename']).then( + lambda: 'characters/instruction-following/', None, shared.gradio['save_root']).then( + chat.generate_instruction_template_yaml, [shared.gradio[k] for k in ['name1_instruct', 'name2_instruct', 'context_instruct', 'turn_template']], shared.gradio['save_contents']).then( + lambda: gr.update(visible=True), None, shared.gradio['file_saver']) - shared.gradio['delete_character'].click( - lambda: [gr.update(visible=True)] * 2, None, [shared.gradio[k] for k in ['delete_character-confirm', 'delete_character-cancel']], show_progress=False) - - shared.gradio['delete_character-cancel'].click( - lambda: [gr.update(visible=False)] * 2, None, [shared.gradio[k] for k in ['delete_character-confirm', 'delete_character-cancel']], show_progress=False) - - shared.gradio['delete_character-confirm'].click( - partial(chat.delete_character, instruct=False), shared.gradio['character_menu'], None).then( - lambda: gr.update(choices=utils.get_available_characters()), outputs=shared.gradio['character_menu']).then( - lambda: 'None', None, shared.gradio['character_menu']).then( - lambda: [gr.update(visible=False)] * 2, None, [shared.gradio[k] for k in ['delete_character-confirm', 'delete_character-cancel']], show_progress=False) + shared.gradio['delete_template'].click( + lambda x: f'{x}.yaml', shared.gradio['instruction_template'], shared.gradio['delete_filename']).then( + lambda: 'characters/instruction-following/', None, shared.gradio['delete_root']).then( + lambda: gr.update(visible=True), None, shared.gradio['file_deleter']) shared.gradio['download_button'].click(lambda x: chat.save_history(x, timestamp=True), shared.gradio['mode'], shared.gradio['download']) shared.gradio['Upload character'].click(chat.upload_character, [shared.gradio['upload_json'], shared.gradio['upload_img_bot']], [shared.gradio['character_menu']]) @@ -975,10 +1018,31 @@ def create_interface(): shared.gradio['Stop'].click(stop_everything_event, None, None, queue=False, cancels=gen_events if shared.args.no_stream else None) shared.gradio['prompt_menu'].change(load_prompt, shared.gradio['prompt_menu'], shared.gradio['textbox'], show_progress=False) - shared.gradio['open_save_prompt'].click(open_save_prompt, None, [shared.gradio[k] for k in ['prompt_to_save', 'open_save_prompt', 'save_prompt']], show_progress=False) - shared.gradio['save_prompt'].click(save_prompt, [shared.gradio[k] for k in ['textbox', 'prompt_to_save']], [shared.gradio[k] for k in ['status', 'prompt_to_save', 'open_save_prompt', 'save_prompt']], show_progress=False) + shared.gradio['save_prompt'].click( + lambda x: x, shared.gradio['textbox'], shared.gradio['save_contents']).then( + lambda: 'prompts/', None, shared.gradio['save_root']).then( + lambda: current_time() + '.txt', None, shared.gradio['save_filename']).then( + lambda: gr.update(visible=True), None, shared.gradio['file_saver']) + + shared.gradio['delete_prompt'].click( + lambda: 'prompts/', None, shared.gradio['delete_root']).then( + lambda x: x + '.txt', shared.gradio['prompt_menu'], shared.gradio['delete_filename']).then( + lambda: gr.update(visible=True), None, shared.gradio['file_deleter']) + shared.gradio['count_tokens'].click(count_tokens, shared.gradio['textbox'], shared.gradio['status'], show_progress=False) + shared.gradio['save_preset'].click( + ui.gather_interface_values, [shared.gradio[k] for k in shared.input_elements], shared.gradio['interface_state']).then( + generate_preset_yaml, shared.gradio['interface_state'], shared.gradio['save_contents']).then( + lambda: 'presets/', None, shared.gradio['save_root']).then( + lambda: 'My Preset.yaml', None, shared.gradio['save_filename']).then( + lambda: gr.update(visible=True), None, shared.gradio['file_saver']) + + shared.gradio['delete_preset'].click( + lambda x: f'{x}.yaml', shared.gradio['preset_menu'], shared.gradio['delete_filename']).then( + lambda: 'presets/', None, shared.gradio['delete_root']).then( + lambda: gr.update(visible=True), None, shared.gradio['file_deleter']) + shared.gradio['interface'].load(lambda: None, None, None, _js=f"() => {{{js}}}") if shared.settings['dark_theme']: shared.gradio['interface'].load(lambda: None, None, None, _js="() => document.getElementsByTagName('body')[0].classList.add('dark')")