diff --git a/modules/async_worker.py b/modules/async_worker.py index 4d36b7367..92eecf298 100644 --- a/modules/async_worker.py +++ b/modules/async_worker.py @@ -30,7 +30,7 @@ def worker(): from PIL import Image, ImageOps from modules.settings import default_settings from modules.resolutions import annotate_resolution_string, get_resolution_string, resolutions, string_to_dimensions - from modules.sdxl_styles import apply_style, apply_wildcards + from modules.sdxl_styles import apply_style, apply_wildcards, style_keys from modules.private_logger import log from modules.expansion import safe_str from modules.util import join_prompts, remove_empty_str, HWC3, resize_image, image_is_generated_in_current_ui @@ -80,18 +80,20 @@ def handler(task): freeu, freeu_b1, freeu_b2, freeu_s1, freeu_s2, \ input_image_checkbox, current_tab, \ uov_method, uov_input_image, outpaint_selections, inpaint_input_image, \ - input_gallery, revision_gallery, keep_input_names = task + use_style_iterator, input_gallery, revision_gallery, keep_input_names = task outpaint_selections = [o.lower() for o in outpaint_selections] loras = [(l1, w1), (l2, w2), (l3, w3), (l4, w4), (l5, w5)] loras_user_raw_input = copy.deepcopy(loras) - raw_style_selections = copy.deepcopy(style_selections) + if use_style_iterator: + style_iterator_pool = style_keys.copy() + for s in style_selections: + style_iterator_pool.remove(s) uov_method = uov_method.lower() - use_style = len(style_selections) > 0 modules.patch.sharpness = sharpness modules.patch.negative_adm = True initial_latent = None @@ -353,8 +355,15 @@ def handler(task): task_seed = seed if same_seed_for_all else seed + i task_prompt = apply_wildcards(prompt, task_seed) + if use_style_iterator and i > 0: # original styles selection goes as 0th image + task_style_selections = style_selections + [style_iterator_pool[i - 1]] + else: + task_style_selections = style_selections + + use_style = len(task_style_selections) > 0 + if use_style: - for s in style_selections: + for s in task_style_selections: p, n = apply_style(s, positive=task_prompt) positive_basic_workloads.append(p) negative_basic_workloads.append(n) @@ -372,6 +381,7 @@ def handler(task): tasks.append(dict( task_seed=task_seed, prompt=task_prompt, + style_selections=task_style_selections, positive=positive_basic_workloads, negative=negative_basic_workloads, positive_top_k=len(positive_basic_workloads), @@ -510,7 +520,7 @@ def callback(step, x0, x, total_steps, y): print(f'Diffusion time: {execution_time:.2f} seconds') metadata = { - 'prompt': raw_prompt, 'negative_prompt': raw_negative_prompt, 'styles': raw_style_selections, + 'prompt': raw_prompt, 'negative_prompt': raw_negative_prompt, 'styles': task['style_selections'], 'real_prompt': task['positive'], 'real_negative_prompt': task['negative'], 'seed': task['task_seed'], 'width': width, 'height': height, 'sampler': sampler_name, 'scheduler': scheduler, 'performance': performance, @@ -557,7 +567,7 @@ def callback(step, x0, x, total_steps, y): ('Prompt', raw_prompt), ('Negative Prompt', raw_negative_prompt), ('Fooocus V2 (Prompt Expansion)', task['expansion']), - ('Styles', str(raw_style_selections)), + ('Styles', str(task['style_selections'])), ('Real Prompt', task['positive']), ('Real Negative Prompt', task['negative']), ('Seed', task['task_seed']), diff --git a/readme.md b/readme.md index c24f087c1..332773278 100644 --- a/readme.md +++ b/readme.md @@ -191,6 +191,7 @@ Below things are already inside the software, and **users do not need to do anyt 26. Support for wildcards (ported from RuinedFooocus - put them in wildcards folder, then try prompts like `__color__ sports car` with different seeds). 27. Support for [FreeU](https://chenyangsi.top/FreeU/). 28. Limited support for non-SDXL models (no refiner, Control-LoRAs, Revision, inpainting, outpainting). +29. Style Iterator (iterates over selected style(s) combined with remaining styles - S1, S1 + S2, S1 + S3, S1 + S4, and so on; for comparing styles pick no initial style, and use same seed for all images). ## Thanks diff --git a/update_log_mre.md b/update_log_mre.md index c7db212ae..ceb1a13d0 100644 --- a/update_log_mre.md +++ b/update_log_mre.md @@ -1,5 +1,6 @@ ### 2.0.78.5 MRE +* Added Style Iterator. * Removed meta tensor usage. ### 2.0.78.4 MRE diff --git a/webui.py b/webui.py index 867314778..b43fdb84c 100644 --- a/webui.py +++ b/webui.py @@ -385,8 +385,10 @@ def clear_default_image(): custom_switch = gr.Slider(label='Custom Switch', minimum=0.2, maximum=1.0, step=0.01, value=settings['custom_switch']) resolution = gr.Dropdown(label='Resolution (width × height)', choices=list(resolutions.keys()), value=settings['resolution'], allow_custom_value=True) style_selections = gr.Dropdown(label='Image Style(s)', choices=style_keys, value=settings['styles'], multiselect=True, max_choices=8) - prompt_expansion = gr.Checkbox(label=fooocus_expansion, value=settings['prompt_expansion']) - image_number = gr.Slider(label='Image Number', minimum=1, maximum=128, step=1, value=settings['image_number']) + with gr.Row(): + prompt_expansion = gr.Checkbox(label=fooocus_expansion, value=settings['prompt_expansion']) + style_iterator = gr.Checkbox(label='Style Iterator', value=False) + image_number = gr.Slider(label='Image Number', minimum=1, maximum=256, step=1, value=settings['image_number']) negative_prompt = gr.Textbox(label='Negative Prompt', show_label=True, placeholder="What you don't want to see.", value=settings['negative_prompt']) with gr.Row(): seed_random = gr.Checkbox(label='Random', value=settings['seed_random']) @@ -425,6 +427,23 @@ def performance_changed(value): performance.change(fn=performance_changed, inputs=[performance], outputs=[custom_row]) + def style_iterator_changed(_style_iterator, _style_selections): + if _style_iterator: + combinations_count = 1 + len(style_keys) - len(_style_selections) # original style selection + all remaining style combinations + return gr.update(interactive=False, value=combinations_count) + else: + return gr.update(interactive=True, value=settings['image_number']) + + def style_selections_changed(_style_iterator, _style_selections): + if _style_iterator: + combinations_count = 1 + len(style_keys) - len(_style_selections) # original style selection + all remaining style combinations + return gr.update(value=combinations_count) + else: + return gr.update() + + style_iterator.change(style_iterator_changed, inputs=[style_iterator, style_selections], outputs=[image_number]) + style_selections.change(style_selections_changed, inputs=[style_iterator, style_selections], outputs=[image_number]) + with gr.Tab(label='Image-2-Image'): revision_mode = gr.Checkbox(label='Revision (prompting with images)', value=settings['revision_mode']) revision_strength_1 = gr.Slider(label='Revision Strength for Image 1', minimum=-2, maximum=2, step=0.01, @@ -611,6 +630,7 @@ def verify_input(img2img, canny, depth, gallery_in, gallery_rev, gallery_out): ctrls += [input_image_checkbox, current_tab] ctrls += [uov_method, uov_input_image] ctrls += [outpaint_selections, inpaint_input_image] + ctrls += [style_iterator] generate_button.click(lambda: (gr.update(visible=True, interactive=True), gr.update(visible=False), []), outputs=[stop_button, generate_button, output_gallery]) \ .then(fn=refresh_seed, inputs=[seed_random, image_seed], outputs=image_seed) \ .then(fn=verify_enhance_image, inputs=[input_image_checkbox, img2img_mode], outputs=[img2img_mode]) \