diff --git a/CHANGELOG.md b/CHANGELOG.md index e09bf53f4..e7898699e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log for SD.Next -## Update for 2023-10-11 +## Update for 2023-10-14 - Final strech of the DEV branch before merge to master: requires pending `diffusers==0.22.0` @@ -178,6 +178,7 @@ or even free speedups and quality improvements (regardless of which workflows yo - **NSFW** - install extension: [NudeNet](https://github.com/vladmandic/sd-extension-nudenet) body part detection, image metadata, advanced censoring, etc... + works for *text*, *image* and *process* workflows more in the extension notes - **General** - **Startup** @@ -198,6 +199,11 @@ or even free speedups and quality improvements (regardless of which workflows yo - **API** - add end-to-end example how to use API: `cli/simple-txt2img.js` covers txt2img, upscale, hires, refiner + - **Extensions** + - better overall compatibility with A1111 extensions (up to a point) + - new framework for extension validation + extensions ui now shows actual status of extensions for reviewed extensions + if you want to contribute/flag/update extension status, reach out on github or discord - **train.py** - wrapper script around built-in **kohya's lora** training script see `cli/train.py --help` diff --git a/extensions-builtin/sd-extension-chainner b/extensions-builtin/sd-extension-chainner index d599c7cbe..aa3050d96 160000 --- a/extensions-builtin/sd-extension-chainner +++ b/extensions-builtin/sd-extension-chainner @@ -1 +1 @@ -Subproject commit d599c7cbe6223290a0e91bcf062dc1770a7d9182 +Subproject commit aa3050d96245430728b682c6b3a5b26a0c475673 diff --git a/javascript/style.css b/javascript/style.css index 5a29a923a..217796950 100644 --- a/javascript/style.css +++ b/javascript/style.css @@ -210,18 +210,6 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt #txt2img_extra_details td:first-child, #img2img_extra_details td:first-child { font-weight: bold; vertical-align: top; } #txt2img_extra_details .gradio-image, #img2img_extra_details .gradio-image { max-height: 70vh; } -/* controlnet -.controlnet_control_type .controlnet_control_type_filter_group .wrap:last-of-type { display: grid; grid-auto-flow: row; grid-template-columns: repeat(4, minmax(0, 1fr)); } -fieldset.controlnet_resize_mode_radio .wrap:last-of-type, fieldset.controlnet_control_mode_radio .wrap:last-of-type { flex-direction: column; } -div.controlnet_preprocessor_model { display: grid; grid-auto-flow: row; grid-template-columns: 1fr max-content; } -div.controlnet_preprocessor_model button.gradio-button { align-self: center; } -div.controlnet_weight_steps > div.form { display: grid; grid-template: repeat(2, 1fr) / repeat(2, 1fr); } -div.controlnet_weight_steps .controlnet_control_weight_slider { grid-column: 1 / -1; } -div.controlnet_image_controls { display: grid; grid-template-columns: repeat(4, 1fr); } -div.controlnet_image_controls .controlnet_invert_warning { grid-column: 1 / -1; } -div.controlnet_image_controls button { justify-self: center; } -div.controlnet_main_options { display: grid; grid-template-columns: 1fr 1fr; grid-auto-flow: row; } - */ /* specific elements */ #modelmerger_interp_description { margin-top: 1em; margin-bottom: 1em; } @@ -229,14 +217,17 @@ div.controlnet_main_options { display: grid; grid-template-columns: 1fr 1fr; gri #scripts_alwayson_txt2img > .label-wrap, #scripts_alwayson_img2img > .label-wrap { background: var(--input-background-fill); padding: 0; margin: 0; border-radius: var(--radius-lg); } #scripts_alwayson_txt2img > .label-wrap > span, #scripts_alwayson_img2img > .label-wrap > span { padding: var(--spacing-xxl); } #script_txt2img_agent_scheduler { display: none; } -#extras_generate, #extras_interrupt, #extras_skip { display: block !important; position: relative; height: 36px; } -#extras_upscale { margin-top: 10px } #refresh_tac_refreshTempFiles { display: none; } #train_tab { flex-flow: row-reverse; } #models_tab { flex-flow: row-reverse; } #swap_axes > button { min-width: 100px; font-size: 1em; } #ui_defaults_review { margin: 1em; } +/* extras */ +.extras { gap: 0.2em 1em !important } +#extras_generate, #extras_interrupt, #extras_skip { display: block !important; position: relative; height: 36px; } +#extras_upscale { margin-top: 10px } + /* log monitor */ .log-monitor { display: none; justify-content: unset !important; overflow: hidden; padding: 0; margin-top: auto; font-family: monospace; font-size: 0.85em; } .log-monitor td, .log-monitor th { padding-left: 1em; } diff --git a/modules/images.py b/modules/images.py index 2d4d2c840..299eaa4d9 100644 --- a/modules/images.py +++ b/modules/images.py @@ -351,6 +351,8 @@ class FilenameGenerator: return shorthash def prompt_words(self): + if self.p is None or self.prompt is None: + return '' no_attention = re_attention.sub(r'\1', self.prompt) no_network = re_network.sub(r'\1', no_attention) no_brackets = re_brackets.sub('', no_network) @@ -419,7 +421,7 @@ class FilenameGenerator: replacement = fun(self, *pattern_args) except Exception as e: replacement = None - shared.log.error(f'Filename apply pattern: {e}') + shared.log.error(f'Filename apply pattern: {x} {e}') if replacement == NOTHING: continue if replacement is not None: @@ -522,7 +524,7 @@ save_thread = threading.Thread(target=atomically_save_image, daemon=True) save_thread.start() -def save_image(image, path, basename, seed=None, prompt=None, extension='jpg', info=None, short_filename=False, no_prompt=False, grid=False, pnginfo_section_name='parameters', p=None, existing_info=None, forced_filename=None, suffix="", save_to_dirs=None): # pylint: disable=unused-argument +def save_image(image, path, basename = '', seed=None, prompt=None, extension=shared.opts.samples_format, info=None, short_filename=False, no_prompt=False, grid=False, pnginfo_section_name='parameters', p=None, existing_info=None, forced_filename=None, suffix="", save_to_dirs=None): # pylint: disable=unused-argument if image is None: shared.log.warning('Image is none') return None, None diff --git a/modules/processing.py b/modules/processing.py index c8ed8a8f0..6705db2a1 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -455,11 +455,17 @@ def fix_seed(p): p.subseed = get_fixed_seed(p.subseed) -def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_subseeds, comments=None, iteration=0, position_in_batch=0, index=None, all_negative_prompts=None): +def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=None, all_subseeds=None, comments=None, iteration=0, position_in_batch=0, index=None, all_negative_prompts=None): if not hasattr(shared.sd_model, 'sd_checkpoint_info'): return '' if index is None: index = position_in_batch + iteration * p.batch_size + if all_prompts is None: + all_prompts = p.all_prompts + if all_seeds is None: + all_seeds = p.all_seeds + if all_subseeds is None: + all_subseeds = p.all_subseeds if all_negative_prompts is None: all_negative_prompts = p.all_negative_prompts comment = ', '.join(comments) if comments is not None and type(comments) is list else None diff --git a/modules/scripts_postprocessing.py b/modules/scripts_postprocessing.py index 75b43887c..29f294b2a 100644 --- a/modules/scripts_postprocessing.py +++ b/modules/scripts_postprocessing.py @@ -88,7 +88,7 @@ class ScriptPostprocessingRunner: def setup_ui(self): inputs = [] for script in self.scripts_in_preferred_order(): - with gr.Accordion(label=script.name) as group: + with gr.Accordion(label=script.name, open=False) as group: self.create_script_ui(script, inputs) script.group = group self.ui_created = True diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index 73727ecc3..4357a1306 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -36,7 +36,11 @@ def get_installed(ext) -> extensions.Extension: def list_extensions(): global extensions_list # pylint: disable=global-statement - extensions_list = shared.readfile(os.path.join(paths.script_path, "html", "extensions.json")) or [] + fn = os.path.join(paths.script_path, "html", "extensions.json") + extensions_list = shared.readfile(fn) or [] + if type(extensions_list) != list: + shared.log.warning(f'Invalid extensions list: file={fn}') + extensions_list = [] found = [] for ext in extensions.extensions: ext.read_info() diff --git a/modules/ui_loadsave.py b/modules/ui_loadsave.py index 16b2df879..fbcf57523 100644 --- a/modules/ui_loadsave.py +++ b/modules/ui_loadsave.py @@ -75,7 +75,7 @@ class UiLoadsave: if x.choices is None: errors.log.warning(f'UI: path={path} value={getattr(x, "value", None)}, choices={getattr(x, "choices", None)}') return False - choices = [c[0] for c in x.choices] if type(x.choices[0]) == tuple else x.choices + choices = [c[0] for c in x.choices] if type(x.choices) == list and len(x.choices) > 0 and type(x.choices[0]) == tuple else x.choices if getattr(x, 'multiselect', False): return all(value in choices for value in val) else: diff --git a/modules/ui_postprocessing.py b/modules/ui_postprocessing.py index 88ec8d45d..b28597653 100644 --- a/modules/ui_postprocessing.py +++ b/modules/ui_postprocessing.py @@ -19,7 +19,7 @@ def submit_click(tab_index, extras_image, image_batch, extras_batch_input_dir, e def create_ui(): tab_index = gr.State(value=0) # pylint: disable=abstract-class-instantiated - with gr.Row(equal_height=False, variant='compact'): + with gr.Row(equal_height=False, variant='compact', elem_classes="extras"): with gr.Column(variant='compact'): with gr.Tabs(elem_id="mode_extras"): with gr.TabItem('Single Image', id="single_image", elem_id="extras_single_tab") as tab_single: