diff --git a/.gitignore b/.gitignore index 9579356..df0f75e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ scripts/__pycache__ config.json config-img2img.json +config-img2img-custom-tracked-components.txt config-txt2img.json +config-txt2img-custom-tracked-components.txt \ No newline at end of file diff --git a/javascript/config_presets.js b/javascript/config_presets.js index 56ad2d9..b97a60e 100644 --- a/javascript/config_presets.js +++ b/javascript/config_presets.js @@ -3,15 +3,17 @@ //...or do it our more precise way: onUiUpdate(function() { //set tooltips - gradioApp().querySelectorAll("#config_presets_open_config_file_button").forEach(el => el.setAttribute("title", "Open the config .json file for manual editing if you want to make changes that way, requires Gradio restart after editing. The txt2img and img2img tabs have separate config files.")) - gradioApp().querySelectorAll("#config_preset_save_textbox").forEach(el => el.setAttribute("title", "The name of a new Config Preset that will be added to the dropdown above")) - gradioApp().querySelectorAll("#config_preset_save_button").forEach(el => el.setAttribute("title", "Save selected fields with the new preset name, then restarts the UI. Overwrites existing preset with the same name.")) - gradioApp().querySelectorAll("#config_preset_add_button").forEach(el => el.setAttribute("title", "[Config Presets] Create or delete a preset")) - gradioApp().querySelectorAll("#config_preset_cancel_save_button").forEach(el => el.setAttribute("title", "Go back")) - gradioApp().querySelectorAll("#config_preset_trash_button").forEach(el => el.setAttribute("title", "Permanently delete selected preset")) - gradioApp().querySelectorAll("#config_preset_fields_to_save > span").forEach(el => el.setAttribute("title", "Only selected field values will be saved with the preset. Unselected fields will be ignored.")) -}) + gradioApp().querySelectorAll("#script_config_preset_open_config_file_button").forEach(el => el.setAttribute("title", "Open the config .json file for manual editing if you want to make changes that way, requires Gradio restart after editing. The txt2img and img2img tabs have separate config files.")) + gradioApp().querySelectorAll("#script_config_preset_save_textbox").forEach(el => el.setAttribute("title", "The name of a new Config Preset that will be added to the dropdown above")) + gradioApp().querySelectorAll("#script_config_preset_save_button").forEach(el => el.setAttribute("title", "Save selected fields with the new preset name, then restarts the UI. Overwrites existing preset with the same name.")) + gradioApp().querySelectorAll("#script_config_preset_add_button").forEach(el => el.setAttribute("title", "[Config Presets] Create or delete a preset")) + gradioApp().querySelectorAll("#script_config_preset_cancel_save_button").forEach(el => el.setAttribute("title", "Go back")) + gradioApp().querySelectorAll("#script_config_preset_trash_button").forEach(el => el.setAttribute("title", "Permanently delete selected preset")) + gradioApp().querySelectorAll("#script_config_preset_fields_to_save > span").forEach(el => el.setAttribute("title", "Only selected field values will be saved with the preset. Unselected fields will be ignored.")) + gradioApp().querySelectorAll("#script_config_preset_open_custom_tracked_components_config").forEach(el => el.setAttribute("title", "Open the config file to add new fields to the above list.")) +}) +/* No longer needed after the bump to Gradio 3.23 //this function called by config_preset_dropdown in config_presets.py function config_preset_dropdown_change() { //when Python changes the enable_hr checkbox in config_preset_dropdown_change() it doesn't fire off the change() JS event, so do this manually @@ -28,7 +30,7 @@ function config_preset_dropdown_change() { //console.log("e="+e) }, 200) //50ms is too fast } - +*/ function config_preset_settings_restart_gradio() { console.log('[Config-Presets] Restarting to apply new config preset...') diff --git a/scripts/config_presets.py b/scripts/config_presets.py index 289e5bd..c4df7cc 100644 --- a/scripts/config_presets.py +++ b/scripts/config_presets.py @@ -8,22 +8,339 @@ import platform import subprocess as sp -BASEDIR = scripts.basedir() #C:\Stable Diffusion\extensions\Config-Presets needs to be set in global space to get the extra 'extensions\Config-Presets' path +BASEDIR = scripts.basedir() #C:\path\to\Stable Diffusion\extensions\Config-Presets needs to be set in global space to get the extra 'extensions\Config-Presets' path +CONFIG_TXT2IMG_CUSTOM_TRACKED_COMPONENTS_FILE_NAME = "config-txt2img-custom-tracked-components.txt" +CONFIG_IMG2IMG_CUSTOM_TRACKED_COMPONENTS_FILE_NAME = "config-img2img-custom-tracked-components.txt" CONFIG_TXT2IMG_FILE_NAME = "config-txt2img.json" CONFIG_IMG2IMG_FILE_NAME = "config-img2img.json" #fields_checkboxgroup = None +def load_txt2img_custom_tracked_component_ids() -> list[str]: + txt2img_custom_tracked_components_ids = [] + try: + with open(f"{BASEDIR}/{CONFIG_TXT2IMG_CUSTOM_TRACKED_COMPONENTS_FILE_NAME}", "r") as file: + for line in file: + line = line.strip() + if not line.startswith("#") and line != "": # ignore lines that start with # or are empty + txt2img_custom_tracked_components_ids.append(line) + #print(f"Added txt2img custom tracked component: {line}") + + except FileNotFoundError: + # config file not found + # First time running the extension or it was deleted, so fill it with default values + txt2img_custom_tracked_components_default_text = """# Put custom txt2img tracked component IDs here. This will allow those fields to be saved as a config preset. +# Lines starting with a # are ignored. +# Component IDs can be found in the HTML (id="...") or in modules/ui.py (elem_id="..."). +# Entering an invalid component ID here will cause this extension to error and not load. +# Note that components on the top row of the UI cannot be added here, such as "setting_sd_model_checkpoint", "setting_sd_vae", and "setting_CLIP_stop_at_last_layers". + +# Other fields: +#txt2img_prompt +#txt2img_neg_prompt +#txt2img_styles +#txt2img_subseed_show +#txt2img_subseed +#txt2img_subseed_strength +#txt2img_seed_resize_from_w +#txt2img_seed_resize_from_h +#txt2img_tiling +#txt2img_hr_resize_x +#txt2img_hr_resize_y + +# Script dropdown: +#script_list + +# X/Y/Z plot (script): +#script_txt2txt_xyz_plot_x_type +#script_txt2txt_xyz_plot_y_type +#script_txt2txt_xyz_plot_z_type +#script_txt2txt_xyz_plot_x_values +#script_txt2txt_xyz_plot_y_values +#script_txt2txt_xyz_plot_z_values + +# Latent Couple (extension): +#cd_txt2img_divisions +#cd_txt2img_positions +#cd_txt2img_weights +#cd_txt2img_end_at_this_step +""" + + write_text_to_file(txt2img_custom_tracked_components_default_text, CONFIG_TXT2IMG_CUSTOM_TRACKED_COMPONENTS_FILE_NAME) + print(f"[Config Presets] txt2img custom tracked components config file not found, created default config at {BASEDIR}/{CONFIG_TXT2IMG_CUSTOM_TRACKED_COMPONENTS_FILE_NAME}") + + return txt2img_custom_tracked_components_ids + + + +def load_img2img_custom_tracked_component_ids() -> list[str]: + img2img_custom_tracked_components_ids = [] + try: + with open(f"{BASEDIR}/{CONFIG_IMG2IMG_CUSTOM_TRACKED_COMPONENTS_FILE_NAME}", "r") as file: + for line in file: + line = line.strip() + if not line.startswith("#") and line != "": # ignore lines that start with # or are empty + img2img_custom_tracked_components_ids.append(line) + #print(f"Added img2img custom tracked component: {line}") + + except FileNotFoundError: + # config file not found + # First time running the extension or it was deleted, so fill it with default values + img2img_custom_tracked_components_ids = """# Put custom img2img tracked component IDs here. This will allow those fields to be saved as a config preset. +# Lines starting with a # are ignored. +# Component IDs can be found in the HTML (id="...") or in modules/ui.py (elem_id="..."). +# Entering an invalid component ID here will cause this extension to error and not load. +# Note that components on the top row of the UI cannot be added here, such as "setting_sd_model_checkpoint", "setting_sd_vae", and "setting_CLIP_stop_at_last_layers". + +# Other fields: +#img2img_prompt +#img2img_neg_prompt +#img2img_mask_mode +#img2img_mask_blur +#img2img_mask_alpha +#img2img_inpainting_fill +#img2img_inpaint_full_res +#img2img_inpaint_full_res_padding +#resize_mode +#img2img_seed +#img2img_subseed_show +#img2img_subseed +#img2img_subseed_strength +#img2img_seed_resize_from_w +#img2img_seed_resize_from_h +#img2img_restore_faces +#img2img_tiling +#img2img_batch_input_dir +#img2img_batch_output_dir +#img2img_batch_inpaint_mask_dir + +# Script dropdown: +#script_list + +# X/Y/Z plot (script): +#script_img2txt_xyz_plot_x_type +#script_img2txt_xyz_plot_y_type +#script_img2txt_xyz_plot_z_type +#script_img2txt_xyz_plot_x_values +#script_img2txt_xyz_plot_y_values +#script_img2txt_xyz_plot_z_values + +# Loopback (script): +#script_loopback_loops +#script_loopback_final_denoising_strength + +# SD upscale (script): +#script_sd_upscale_overlap +#script_sd_upscale_scale_factor +#script_sd_upscale_upscaler_index + +# Latent Couple (extension): +#cd_img2img_divisions +#cd_img2img_positions +#cd_img2img_weights +#cd_img2img_end_at_this_step +""" + + write_text_to_file(img2img_custom_tracked_components_ids, CONFIG_IMG2IMG_CUSTOM_TRACKED_COMPONENTS_FILE_NAME) + print(f"[Config Presets] img2img custom tracked components config file not found, created default config at {BASEDIR}/{CONFIG_TXT2IMG_CUSTOM_TRACKED_COMPONENTS_FILE_NAME}") + + return img2img_custom_tracked_components_ids + + +def load_txt2img_config_file(): + try: + with open(f"{BASEDIR}/{CONFIG_TXT2IMG_FILE_NAME}") as file: + txt2img_config_presets = json.load(file) + + except FileNotFoundError: + # txt2img config file not found + # First time running the extension or it was deleted, so fill it with default values + txt2img_config_presets = { + "None": {}, + "Low quality ------ 512x512, steps: 10, batch size: 8, DPM++ 2M Karras": { + "txt2img_sampling": "DPM++ 2M Karras", + "txt2img_steps": 10, + "txt2img_width": 512, + "txt2img_height": 512, + "txt2img_enable_hr": False, + "txt2img_batch_count": 1, + "txt2img_batch_size": 8, + # "txt2img_cfg_scale": 7, + }, + "Medium quality - 512x512, steps: 15, batch size: 4, DPM++ 2M Karras": { + "txt2img_sampling": "DPM++ 2M Karras", + "txt2img_steps": 15, + "txt2img_width": 512, + "txt2img_height": 512, + "txt2img_enable_hr": False, + "txt2img_batch_count": 1, + "txt2img_batch_size": 4, + # "txt2img_cfg_scale": 7, + }, + "High quality ------ 512x512, steps: 20, batch size: 4, DPM++ 2S a Karras": { + "txt2img_sampling": "DPM++ 2S a Karras", + "txt2img_steps": 20, + "txt2img_width": 512, + "txt2img_height": 512, + "txt2img_enable_hr": False, + "txt2img_batch_count": 1, + "txt2img_batch_size": 4, + # "txt2img_cfg_scale": 7, + }, + "Low quality ------ 768x768, steps: 10, batch size: 8, DPM++ 2M Karras": { + "txt2img_sampling": "DPM++ 2M Karras", + "txt2img_steps": 10, + "txt2img_width": 768, + "txt2img_height": 768, + "txt2img_enable_hr": False, + "txt2img_batch_count": 1, + "txt2img_batch_size": 8, + # "txt2img_cfg_scale": 7, + }, + "Medium quality - 768x768, steps: 15, batch size: 4, DPM++ 2M Karras": { + "txt2img_sampling": "DPM++ 2M Karras", + "txt2img_steps": 15, + "txt2img_width": 768, + "txt2img_height": 768, + "txt2img_enable_hr": False, + "txt2img_batch_count": 1, + "txt2img_batch_size": 4, + # "txt2img_cfg_scale": 7, + }, + "High quality ------ 768x768, steps: 20, batch size: 4, DPM++ 2S a Karras": { + "txt2img_sampling": "DPM++ 2S a Karras", + "txt2img_steps": 20, + "txt2img_width": 768, + "txt2img_height": 768, + "txt2img_enable_hr": False, + "txt2img_batch_count": 1, + "txt2img_batch_size": 4, + # "txt2img_cfg_scale": 7, + }, + "High res -------- 1024x1024, steps: 30, batch size: 1, DPM++ 2M Karras, [Upscale by: 2, Denoising: 0.4, Hires steps: 10]": { + "txt2img_steps": 30, + "txt2img_sampling": "DPM++ 2M Karras", + "txt2img_width": 512, + "txt2img_height": 512, + "txt2img_enable_hr": True, + "txt2img_hr_scale": 2, + "txt2img_hires_steps": 10, + "txt2img_denoising_strength": 0.4, + "txt2img_batch_count": 1, + "txt2img_batch_size": 1, + # "txt2img_cfg_scale": 7, + }, + "1080p ----------- 1920x1080, steps: 20, batch size: 1, DPM++ 2S a Karras, [Upscale by: 2.5, Denoising: 0.4, Hires steps: 10]": { + # 2x 960x536, 2.5x 768x432, 3x 640x360 + "txt2img_steps": 20, + "txt2img_sampling": "DPM++ 2S a Karras", + "txt2img_width": 768, + "txt2img_height": 432, + "txt2img_enable_hr": True, + "txt2img_hr_scale": 2.5, + "txt2img_hires_steps": 10, + "txt2img_denoising_strength": 0.4, + "txt2img_batch_count": 1, + "txt2img_batch_size": 1, + # "txt2img_cfg_scale": 7, + }, + "1440p ----------- 2560x1440, steps: 25, batch size: 1, DPM++ 2S a Karras, [Upscale by: 3.3334, Denoising: 0.3, Hires steps: 10]": { + # 2x 1024x720, 2.5x 1024x576, 3.3334x 768x432, 4x 640x360 + "txt2img_steps": 25, + "txt2img_sampling": "DPM++ 2S a Karras", + "txt2img_width": 768, + "txt2img_height": 432, + "txt2img_enable_hr": True, + "txt2img_hr_scale": 3.3334, + "txt2img_hires_steps": 10, + "txt2img_denoising_strength": 0.3, + "txt2img_batch_count": 1, + "txt2img_batch_size": 1, + # "txt2img_cfg_scale": 7, + }, + "4k ---------------- 3840x2160, steps: 30, batch size: 1, DPM++ 2S a Karras, [Upscale by: 5, Denoising: 0.3, Hires steps: 15]": { + # 2x 1420x1080, 2.5x 1536x864, 3x 1280x720, 5x 768x432, 6x 640x360 + "txt2img_steps": 30, + "txt2img_sampling": "DPM++ 2S a Karras", + "txt2img_width": 768, + "txt2img_height": 432, + "txt2img_enable_hr": True, + "txt2img_hr_scale": 5, + "txt2img_hires_steps": 15, + "txt2img_denoising_strength": 0.3, + "txt2img_batch_count": 1, + "txt2img_batch_size": 1, + # "txt2img_cfg_scale": 7, + }, + } + + write_json_to_file(txt2img_config_presets, CONFIG_TXT2IMG_FILE_NAME) + print(f"[Config Presets] txt2img config file not found, created default config at {BASEDIR}/{CONFIG_TXT2IMG_FILE_NAME}") + + return txt2img_config_presets + + +def load_img2img_config_file(): + try: + with open(f"{BASEDIR}/{CONFIG_IMG2IMG_FILE_NAME}") as file: + img2img_config_presets = json.load(file) + + except FileNotFoundError: + # img2img config file not found + # First time running the extension or it was deleted, so fill it with default values + img2img_config_presets = { + "None": {}, + "Low denoising ------- 512x512, denoising: 0.25, steps: 10, DPM++ 2M Karras": { + "img2img_sampling": "DPM++ 2M Karras", + "img2img_steps": 10, + "img2img_width": 512, + "img2img_height": 512, + # "img2img_batch_count": 1, + # "img2img_batch_size": 1, + # "img2img_cfg_scale": 7, + "img2img_denoising_strength": 0.25, + }, + "Medium denoising -- 512x512, denoising: 0.50, steps: 15, DPM++ 2M Karras": { + "img2img_sampling": "DPM++ 2M Karras", + "img2img_steps": 15, + "img2img_width": 512, + "img2img_height": 512, + # "img2img_batch_count": 1, + # "img2img_batch_size": 1, + # "img2img_cfg_scale": 7, + "img2img_denoising_strength": 0.50, + }, + "High denoising ------- 512x512, denoising: 0.75, steps: 20, DPM++ 2M Karras": { + "img2img_sampling": "DPM++ 2M Karras", + "img2img_steps": 20, + "img2img_width": 512, + "img2img_height": 512, + # "img2img_batch_count": 1, + # "img2img_batch_size": 1, + # "img2img_cfg_scale": 7, + "img2img_denoising_strength": 0.75, + }, + } + + write_json_to_file(img2img_config_presets, CONFIG_IMG2IMG_FILE_NAME) + print(f"[Config Presets] img2img config file not found, created default config at {BASEDIR}/{CONFIG_IMG2IMG_FILE_NAME}") + + return img2img_config_presets + + + class Script(scripts.Script): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - #self.txt2img_config_preset_dropdown = None + # Load custom tracked components + txt2img_custom_tracked_components_ids = load_txt2img_custom_tracked_component_ids() + img2img_custom_tracked_components_ids = load_img2img_custom_tracked_component_ids() # These are the settings from the UI that are saved for each preset - self.txt2img_component_ids = [ # mirrors the config_preset_dropdown.change(output) events and config_preset_dropdown_change() + self.txt2img_component_ids = [ "txt2img_sampling", "txt2img_steps", "txt2img_width", @@ -37,9 +354,10 @@ class Script(scripts.Script): "txt2img_hires_steps", "txt2img_denoising_strength", "txt2img_cfg_scale", - ] - self.img2img_component_ids = [ # mirrors the config_preset_dropdown.change(output) events and config_preset_dropdown_change() + self.txt2img_component_ids += txt2img_custom_tracked_components_ids # add the custom tracked components + + self.img2img_component_ids = [ "img2img_sampling", "img2img_steps", "img2img_width", @@ -50,200 +368,22 @@ class Script(scripts.Script): "img2img_denoising_strength", "img2img_restore_faces", ] + self.img2img_component_ids += img2img_custom_tracked_components_ids # add the custom tracked components # Mapping between component labels and the actual components in ui.py self.txt2img_component_map = {k: None for k in self.txt2img_component_ids} # gets filled up in the after_component() method self.img2img_component_map = {k: None for k in self.img2img_component_ids} # gets filled up in the after_component() method # Load txt2img and img2img config files - try: - with open(f"{BASEDIR}/{CONFIG_TXT2IMG_FILE_NAME}") as file: - self.txt2img_config_presets = json.load(file) + self.txt2img_config_presets = load_txt2img_config_file() + self.img2img_config_presets = load_img2img_config_file() - # #print("self.config_presets loaded:") - # for preset_name, values_dict in self.txt2img_config_presets.items(): - # #print(preset_name,values_dict) - # if "steps" in values_dict.keys(): - # print("[ERROR][Config-Presets] Your config.json file is using an outdated format, so the Config Presets dropdown will not work. You need to delete /extensions/Config-Presets/config.json so it can be recreated with the new updated format.") - # break - - - except FileNotFoundError: - # txt2img config file not found - # First time running the extension or it was deleted, so fill it with default values - self.txt2img_config_presets = { - "None": {}, - "Low quality ------ 512x512, steps: 10, batch size: 8, DPM++ 2M Karras": { - "txt2img_sampling": "DPM++ 2M Karras", - "txt2img_steps": 10, - "txt2img_width": 512, - "txt2img_height": 512, - "txt2img_enable_hr": False, - "txt2img_batch_count": 1, - "txt2img_batch_size": 8, - #"txt2img_cfg_scale": 7, - }, - "Medium quality - 512x512, steps: 15, batch size: 4, DPM++ 2M Karras": { - "txt2img_sampling": "DPM++ 2M Karras", - "txt2img_steps": 15, - "txt2img_width": 512, - "txt2img_height": 512, - "txt2img_enable_hr": False, - "txt2img_batch_count": 1, - "txt2img_batch_size": 4, - #"txt2img_cfg_scale": 7, - }, - "High quality ------ 512x512, steps: 20, batch size: 4, DPM++ 2S a Karras": { - "txt2img_sampling": "DPM++ 2S a Karras", - "txt2img_steps": 20, - "txt2img_width": 512, - "txt2img_height": 512, - "txt2img_enable_hr": False, - "txt2img_batch_count": 1, - "txt2img_batch_size": 4, - #"txt2img_cfg_scale": 7, - }, - "Low quality ------ 768x768, steps: 10, batch size: 8, DPM++ 2M Karras": { - "txt2img_sampling": "DPM++ 2M Karras", - "txt2img_steps": 10, - "txt2img_width": 768, - "txt2img_height": 768, - "txt2img_enable_hr": False, - "txt2img_batch_count": 1, - "txt2img_batch_size": 8, - #"txt2img_cfg_scale": 7, - }, - "Medium quality - 768x768, steps: 15, batch size: 4, DPM++ 2M Karras": { - "txt2img_sampling": "DPM++ 2M Karras", - "txt2img_steps": 15, - "txt2img_width": 768, - "txt2img_height": 768, - "txt2img_enable_hr": False, - "txt2img_batch_count": 1, - "txt2img_batch_size": 4, - #"txt2img_cfg_scale": 7, - }, - "High quality ------ 768x768, steps: 20, batch size: 4, DPM++ 2S a Karras": { - "txt2img_sampling": "DPM++ 2S a Karras", - "txt2img_steps": 20, - "txt2img_width": 768, - "txt2img_height": 768, - "txt2img_enable_hr": False, - "txt2img_batch_count": 1, - "txt2img_batch_size": 4, - #"txt2img_cfg_scale": 7, - }, - "High res -------- 1024x1024, steps: 30, batch size: 1, DPM++ 2M Karras, [Upscale by: 2, Denoising: 0.3, Hires steps: 10]": { - "txt2img_steps": 30, - "txt2img_sampling": "DPM++ 2M Karras", - "txt2img_width": 512, - "txt2img_height": 512, - "txt2img_enable_hr": True, - "txt2img_hr_scale": 2, - "txt2img_hires_steps": 10, - "txt2img_denoising_strength": 0.3, - "txt2img_batch_count": 1, - "txt2img_batch_size": 1, - #"txt2img_cfg_scale": 7, - }, - "1080p ----------- 1920x1080, steps: 20, batch size: 1, DPM++ 2S a Karras, [Upscale by: 2.5, Denoising: 0.3, Hires steps: 10]": { - #2x 960x536, 2.5x 768x432, 3x 640x360 - "txt2img_steps": 20, - "txt2img_sampling": "DPM++ 2S a Karras", - "txt2img_width": 768, - "txt2img_height": 432, - "txt2img_enable_hr": True, - "txt2img_hr_scale": 2.5, - "txt2img_hires_steps": 10, - "txt2img_denoising_strength": 0.3, - "txt2img_batch_count": 1, - "txt2img_batch_size": 1, - #"txt2img_cfg_scale": 7, - }, - "1440p ----------- 2560x1440, steps: 25, batch size: 1, DPM++ 2S a Karras, [Upscale by: 3.3334, Denoising: 0.3, Hires steps: 10]": { - #2x 1024x720, 2.5x 1024x576, 3.3334x 768x432, 4x 640x360 - "txt2img_steps": 25, - "txt2img_sampling": "DPM++ 2S a Karras", - "txt2img_width": 768, - "txt2img_height": 432, - "txt2img_enable_hr": True, - "txt2img_hr_scale": 3.3334, - "txt2img_hires_steps": 10, - "txt2img_denoising_strength": 0.3, - "txt2img_batch_count": 1, - "txt2img_batch_size": 1, - #"txt2img_cfg_scale": 7, - }, - "4k ---------------- 3840x2160, steps: 30, batch size: 1, DPM++ 2S a Karras, [Upscale by: 5, Denoising: 0.3, Hires steps: 15]": { - #2x 1420x1080, 2.5x 1536x864, 3x 1280x720, 5x 768x432, 6x 640x360 - "txt2img_steps": 30, - "txt2img_sampling": "DPM++ 2S a Karras", - "txt2img_width": 768, - "txt2img_height": 432, - "txt2img_enable_hr": True, - "txt2img_hr_scale": 5, - "txt2img_hires_steps": 15, - "txt2img_denoising_strength": 0.3, - "txt2img_batch_count": 1, - "txt2img_batch_size": 1, - #"txt2img_cfg_scale": 7, - }, - } - - write_config_presets_to_file(self.txt2img_config_presets, CONFIG_TXT2IMG_FILE_NAME) - print(f"[Config Presets] txt2img config file not found, created default config at {BASEDIR}/{CONFIG_TXT2IMG_FILE_NAME}") - - - try: - with open(f"{BASEDIR}/{CONFIG_IMG2IMG_FILE_NAME}") as file: - self.img2img_config_presets = json.load(file) - - except FileNotFoundError: - # img2img config file not found - # First time running the extension or it was deleted, so fill it with default values - self.img2img_config_presets = { - "None": {}, - "Low denoising ------- 512x512, denoising: 0.25, steps: 10, DPM++ 2M Karras": { - "img2img_sampling": "DPM++ 2M Karras", - "img2img_steps": 10, - "img2img_width": 512, - "img2img_height": 512, - #"img2img_batch_count": 1, - #"img2img_batch_size": 1, - #"img2img_cfg_scale": 7, - "img2img_denoising_strength": 0.25, - }, - "Medium denoising -- 512x512, denoising: 0.50, steps: 15, DPM++ 2M Karras": { - "img2img_sampling": "DPM++ 2M Karras", - "img2img_steps": 15, - "img2img_width": 512, - "img2img_height": 512, - #"img2img_batch_count": 1, - #"img2img_batch_size": 1, - #"img2img_cfg_scale": 7, - "img2img_denoising_strength": 0.50, - }, - "High denoising ------- 512x512, denoising: 0.75, steps: 20, DPM++ 2M Karras": { - "img2img_sampling": "DPM++ 2M Karras", - "img2img_steps": 20, - "img2img_width": 512, - "img2img_height": 512, - #"img2img_batch_count": 1, - #"img2img_batch_size": 1, - #"img2img_cfg_scale": 7, - "img2img_denoising_strength": 0.75, - }, - } - - write_config_presets_to_file(self.img2img_config_presets, CONFIG_IMG2IMG_FILE_NAME) - print(f"[Config Presets] img2img config file not found, created default config at {BASEDIR}/{CONFIG_IMG2IMG_FILE_NAME}") def title(self): return "Config Presets" def show(self, is_img2img): - #return True return scripts.AlwaysVisible # hide this script in the Scripts dropdown def after_component(self, component, **kwargs): @@ -252,14 +392,17 @@ class Script(scripts.Script): component_map = None component_ids = None config_file_name = None + custom_tracked_components_config_file_name = None if self.is_txt2img: component_map = self.txt2img_component_map component_ids = self.txt2img_component_ids config_file_name = CONFIG_TXT2IMG_FILE_NAME + custom_tracked_components_config_file_name = CONFIG_TXT2IMG_CUSTOM_TRACKED_COMPONENTS_FILE_NAME else: component_map = self.img2img_component_map component_ids = self.img2img_component_ids config_file_name = CONFIG_IMG2IMG_FILE_NAME + custom_tracked_components_config_file_name = CONFIG_IMG2IMG_CUSTOM_TRACKED_COMPONENTS_FILE_NAME #if component.label in self.component_map: if component.elem_id in component_map: @@ -277,7 +420,7 @@ class Script(scripts.Script): for component_name, component in component_map.items(): #print(component_name, component_type) if component is None: - print(f"[ERROR][Config-Presets] The component '{component_name}' no longer exists in the Web UI. Try updating the Config-Presets extension. This extension will not work until this issue is resolved.") + print(f"[ERROR][Config-Presets] The component '{component_name}' could not be processed. This may be because you are running an outdated version of the Config-Presets extension, or you included a component ID in the custom tracked components config file that does not exist or is an invalid component. This extension will not work until this issue is resolved.") return # Mark components with type "index" to be transform @@ -304,7 +447,7 @@ class Script(scripts.Script): label="Fields to save", show_label=True, interactive=True, - elem_id="config_preset_fields_to_save", + elem_id="script_config_preset_fields_to_save", ).unrender() #we need to define this early on so that it can be used as an input for another function with gr.Column(min_width=600, elem_id="config_preset_wrapper_txt2img" if self.is_txt2img else "config_preset_wrapper_img2img"): # pushes our stuff onto a new row at 1080p screen resolution @@ -317,7 +460,7 @@ class Script(scripts.Script): print(f"[Config-Presets] Changed to: {dropdown_value}") # update component values with user preset - current_components = dict(zip(component_map.keys(),components_value)) + current_components = dict(zip(component_map.keys(), components_value)) #print("Components before:", current_components) current_components.update(config_preset) @@ -325,7 +468,7 @@ class Script(scripts.Script): for component_name, component_value in current_components.items(): #print(component_name, component_value) if component_name in index_type_components and type(component_value) == int: - current_components[component_name] = component_map[component_name].choices[component_value] + current_components[component_name] = component_map[component_name].choices[component_value] #print("Components after :", current_components) @@ -352,12 +495,13 @@ class Script(scripts.Script): print(traceback.format_exc()) # prints the exception stacktrace print("[ERROR][CRITICAL][Config-Presets] The Config-Presets extension encountered a fatal error. A component required by this extension no longer exists in the Web UI. This is most likely due to the A1111 Web UI being updated. Try updating the Config-Presets extension. If that doesn't work, please post a bug report at https://github.com/Zyin055/Config-Presets/issues and delete your extensions/Config-Presets folder until an update is published.") - config_preset_dropdown.change( - fn=None, - inputs=[], - outputs=[], - _js="function() { config_preset_dropdown_change() }", # JS is used to update the Hires fix row to show/hide it - ) + # No longer needed after the bump to Gradio 3.23 + # config_preset_dropdown.change( + # fn=None, + # inputs=[], + # outputs=[], + # _js="function() { config_preset_dropdown_change() }", # JS is used to update the Hires fix row to show/hide it + # ) with gr.Column(scale=8, min_width=100, visible=False) as collapsable_column: with gr.Row(): with gr.Column(scale=1, min_width=10): @@ -367,7 +511,7 @@ class Script(scripts.Script): del config_presets[config_preset_name] print(f'Config Presets: deleted "{config_preset_name}"') - write_config_presets_to_file(config_presets, config_file_name) + write_json_to_file(config_presets, config_file_name) preset_keys = list(config_presets.keys()) return gr.Dropdown.update(value=preset_keys[len(preset_keys)-1], choices=preset_keys) @@ -375,7 +519,7 @@ class Script(scripts.Script): trash_button = gr.Button( value="\U0001F5D1", - elem_id="config_preset_trash_button", + elem_id="script_config_preset_trash_button", ) trash_button.click( fn=delete_selected_preset, @@ -401,7 +545,7 @@ class Script(scripts.Script): open_config_file_button = gr.Button( value="📂 Open config file...", - elem_id="config_presets_open_config_file_button", + elem_id="script_config_preset_open_config_file_button", ) open_config_file_button.click( fn=lambda: open_file(f"{BASEDIR}/{config_file_name}"), @@ -412,13 +556,13 @@ class Script(scripts.Script): with gr.Column(scale=2, min_width=50): cancel_button = gr.Button( value="Cancel", - elem_id="config_preset_cancel_save_button", + elem_id="script_config_preset_cancel_save_button", ) with gr.Column(scale=1, min_width=120, visible=True) as add_remove_button_column: add_remove_button = gr.Button( value="Add/Remove...", - elem_id="config_preset_add_button", + elem_id="script_config_preset_add_button", ) with gr.Row() as collapsable_row: @@ -431,14 +575,14 @@ class Script(scripts.Script): placeholder="Ex: Low quality", # value="My Preset", max_lines=1, - elem_id="config_preset_save_textbox", + elem_id="script_config_preset_save_textbox", ) with gr.Column(scale=2, min_width=200): save_button = gr.Button( # value="Create", value="💾 Save & Restart", variant="primary", - elem_id="config_preset_save_button", + elem_id="script_config_preset_save_button", ) save_button.click( @@ -484,6 +628,20 @@ class Script(scripts.Script): with gr.Row(): fields_checkboxgroup.render() + with gr.Row(): + with gr.Column(scale=1): + open_custom_tracked_components_config_file_button = gr.Button( + value="📂 Add custom fields...", + elem_id="script_config_preset_open_custom_tracked_components_config", + ) + open_custom_tracked_components_config_file_button.click( + fn=lambda: open_file(f"{BASEDIR}/{custom_tracked_components_config_file_name}"), + inputs=[], + outputs=[], + ) + with gr.Column(scale=2): + pass + def ui(self, is_img2img): pass @@ -530,7 +688,7 @@ def save_config(config_presets, component_map, config_file_name): #print(f"new_setting_map = {new_setting_map}") config_presets.update({new_setting_name: new_setting_map}) - write_config_presets_to_file(config_presets, config_file_name) + write_json_to_file(config_presets, config_file_name) # print(f"self.txt2img_config_preset_dropdown.choices before =\n{self.txt2img_config_preset_dropdown.choices}") # self.txt2img_config_preset_dropdown.choices = list(config_presets.keys()) @@ -549,7 +707,11 @@ def save_config(config_presets, component_map, config_file_name): return func -def write_config_presets_to_file(config_presets, config_file_name: str): - json_object = json.dumps(config_presets, indent=4) - with open(f"{BASEDIR}/{config_file_name}", "w") as outfile: - outfile.write(json_object) +def write_json_to_file(json_data, file_name: str): + with open(f"{BASEDIR}/{file_name}", "w") as file: + file.write(json.dumps(json_data, indent=4)) + + +def write_text_to_file(text, file_name: str): + with open(f"{BASEDIR}/{file_name}", "w") as file: + file.write(text)