diff --git a/CHANGELOG.md b/CHANGELOG.md index a987b5f06..c5d707b33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,8 +26,15 @@ - **Schedulers**: - [TDD](https://github.com/RedAIGC/Target-Driven-Distillation) new super-fast scheduler that can generate images in 4-8 steps recommended to use with [TDD LoRA](https://huggingface.co/RED-AIGC/TDD/tree/main) +- **Detailer**: + - add explicit detailer prompt and negative prompt + - move steps, strength, prompt, negative from settings into ui params + - set/restore detailer metadata + - new [detailer wiki](https://github.com/vladmandic/automatic/wiki/Detailer) +- **XYZ Grid** + - add prompt search&replace options: *primary, refine, detailer, all* - [Wiki/Docs](https://vladmandic.github.io/sdnext-docs/): - - updated: install, debug, control-howto, zluda + - updated: Detailer, Install, Debug, Control-HowTo, ZLUDA - **Fixes**: - explict clear caches on model load - lock adetailer commit: `#a89c01d` diff --git a/modules/control/run.py b/modules/control/run.py index 8cecb93af..b96718e0d 100644 --- a/modules/control/run.py +++ b/modules/control/run.py @@ -222,7 +222,8 @@ def control_run(state: str = '', steps: int = 20, sampler_index: int = None, seed: int = -1, subseed: int = -1, subseed_strength: float = 0, seed_resize_from_h: int = -1, seed_resize_from_w: int = -1, cfg_scale: float = 6.0, clip_skip: float = 1.0, image_cfg_scale: float = 6.0, diffusers_guidance_rescale: float = 0.7, pag_scale: float = 0.0, pag_adaptive: float = 0.5, cfg_end: float = 1.0, - full_quality: bool = True, detailer: bool = False, tiling: bool = False, hidiffusion: bool = False, + full_quality: bool = True, tiling: bool = False, hidiffusion: bool = False, + detailer_enabled: bool = True, detailer_prompt: str = '', detailer_negative: str = '', detailer_steps: int = 10, detailer_strength: float = 0.3, hdr_mode: int = 0, hdr_brightness: float = 0, hdr_color: float = 0, hdr_sharpen: float = 0, hdr_clamp: bool = False, hdr_boundary: float = 4.0, hdr_threshold: float = 0.95, hdr_maximize: bool = False, hdr_max_center: float = 0.6, hdr_max_boundry: float = 1.0, hdr_color_picker: str = None, hdr_tint_ratio: float = 0, resize_mode_before: int = 0, resize_name_before: str = 'None', resize_context_before: str = 'None', width_before: int = 512, height_before: int = 512, scale_by_before: float = 1.0, selected_scale_tab_before: int = 0, @@ -286,9 +287,14 @@ def control_run(state: str = '', pag_scale = pag_scale, pag_adaptive = pag_adaptive, full_quality = full_quality, - detailer = detailer, tiling = tiling, hidiffusion = hidiffusion, + # detailer + detailer_enabled = detailer_enabled, + detailer_prompt = detailer_prompt, + detailer_negative = detailer_negative, + detailer_steps = detailer_steps, + detailer_strength = detailer_strength, # resize resize_mode = resize_mode_before if resize_name_before != 'None' else 0, resize_name = resize_name_before, diff --git a/modules/img2img.py b/modules/img2img.py index 2e3eca54d..7a5a33cd0 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -139,7 +139,8 @@ def img2img(id_task: str, state: str, mode: int, sampler_index, mask_blur, mask_alpha, inpainting_fill, - full_quality, detailer, tiling, hidiffusion, + full_quality, tiling, hidiffusion, + detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, n_iter, batch_size, cfg_scale, image_cfg_scale, diffusers_guidance_rescale, @@ -158,14 +159,15 @@ def img2img(id_task: str, state: str, mode: int, hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundry, hdr_color_picker, hdr_tint_ratio, enable_hr, hr_sampler_index, hr_denoising_strength, hr_resize_mode, hr_resize_context, hr_upscaler, hr_force, hr_second_pass_steps, hr_scale, hr_resize_x, hr_resize_y, refiner_steps, hr_refiner_start, refiner_prompt, refiner_negative, override_settings_texts, - *args): # pylint: disable=unused-argument + *args): + + + debug(f'img2img: {id_task}') if shared.sd_model is None: shared.log.warning('Aborted: op=img model not loaded') return [], '', '', 'Error: model not loaded' - debug(f'img2img: id_task={id_task}|mode={mode}|prompt={prompt}|negative_prompt={negative_prompt}|prompt_styles={prompt_styles}|init_img={init_img}|sketch={sketch}|init_img_with_mask={init_img_with_mask}|inpaint_color_sketch={inpaint_color_sketch}|inpaint_color_sketch_orig={inpaint_color_sketch_orig}|init_img_inpaint={init_img_inpaint}|init_mask_inpaint={init_mask_inpaint}|steps={steps}|sampler_index={sampler_index}||mask_blur={mask_blur}|mask_alpha={mask_alpha}|inpainting_fill={inpainting_fill}|full_quality={full_quality}|detailer={detailer}|tiling={tiling}|hidiffusion={hidiffusion}|n_iter={n_iter}|batch_size={batch_size}|cfg_scale={cfg_scale}|image_cfg_scale={image_cfg_scale}|clip_skip={clip_skip}|denoising_strength={denoising_strength}|seed={seed}|subseed{subseed}|subseed_strength={subseed_strength}|seed_resize_from_h={seed_resize_from_h}|seed_resize_from_w={seed_resize_from_w}|selected_scale_tab={selected_scale_tab}|height={height}|width={width}|scale_by={scale_by}|resize_mode={resize_mode}|resize_name={resize_name}|resize_context={resize_context}|inpaint_full_res={inpaint_full_res}|inpaint_full_res_padding={inpaint_full_res_padding}|inpainting_mask_invert={inpainting_mask_invert}|img2img_batch_files={img2img_batch_files}|img2img_batch_input_dir={img2img_batch_input_dir}|img2img_batch_output_dir={img2img_batch_output_dir}|img2img_batch_inpaint_mask_dir={img2img_batch_inpaint_mask_dir}|override_settings_texts={override_settings_texts}') - if sampler_index is None: shared.log.warning('Sampler: invalid') sampler_index = 0 @@ -240,9 +242,13 @@ def img2img(id_task: str, state: str, mode: int, width=width, height=height, full_quality=full_quality, - detailer=detailer, tiling=tiling, hidiffusion=hidiffusion, + detailer_enabled=detailer_enabled, + detailer_prompt=detailer_prompt, + detailer_negative=detailer_negative, + detailer_steps=detailer_steps, + detailer_strength=detailer_strength, init_images=[image], mask=mask, mask_blur=mask_blur, diff --git a/modules/postprocess/yolo.py b/modules/postprocess/yolo.py index 4011147ec..44016c18b 100644 --- a/modules/postprocess/yolo.py +++ b/modules/postprocess/yolo.py @@ -207,8 +207,8 @@ class YoloRestorer(Detailer): resolution = 512 if shared.sd_model_type in ['none', 'sd', 'lcm', 'unknown'] else 1024 orig_prompt: str = orig_p.get('all_prompts', [''])[0] orig_negative: str = orig_p.get('all_negative_prompts', [''])[0] - prompt: str = orig_p.get('refiner_prompt', '') - negative: str = orig_p.get('refiner_negative', '') + prompt: str = orig_p.get('detailer_prompt', '') + negative: str = orig_p.get('detailer_negative', '') if len(prompt) == 0: prompt = orig_prompt else: @@ -230,9 +230,9 @@ class YoloRestorer(Detailer): 'n_iter': 1, 'prompt': prompt, 'negative_prompt': negative, - 'denoising_strength': shared.opts.detailer_strength, + 'denoising_strength': p.detailer_strength, 'sampler_name': orig_p.get('hr_sampler_name', 'default'), - 'steps': shared.opts.detailer_steps, + 'steps': p.detailer_steps, 'styles': [], 'inpaint_full_res': True, 'inpainting_mask_invert': 0, @@ -309,7 +309,6 @@ class YoloRestorer(Detailer): def ui_settings_change(detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps): shared.opts.detailer_models = detailers shared.opts.detailer_classes = classes - shared.opts.detailer_strength = strength shared.opts.detailer_padding = padding shared.opts.detailer_blur = blur shared.opts.detailer_conf = min_confidence @@ -317,9 +316,8 @@ class YoloRestorer(Detailer): shared.opts.detailer_min_size = min_size shared.opts.detailer_max_size = max_size shared.opts.detailer_iou = iou - shared.opts.detailer_steps = steps shared.opts.save(shared.config_filename, silent=True) - shared.log.debug(f'Detailer settings: models={shared.opts.detailer_models} classes={shared.opts.detailer_classes} strength={shared.opts.detailer_strength} conf={shared.opts.detailer_conf} max={shared.opts.detailer_max} iou={shared.opts.detailer_iou} size={shared.opts.detailer_min_size}-{shared.opts.detailer_max_size} padding={shared.opts.detailer_padding} steps={shared.opts.detailer_steps}') + shared.log.debug(f'Detailer settings: models={detailers} classes={classes} strength={strength} conf={min_confidence} max={max_detected} iou={iou} size={min_size}-{max_size} padding={padding} steps={steps}') with gr.Accordion(open=False, label="Detailer", elem_id=f"{tab}_detailer_accordion", elem_classes=["small-accordion"], visible=shared.native): with gr.Row(): @@ -330,8 +328,12 @@ class YoloRestorer(Detailer): with gr.Row(): classes = gr.Textbox(label="Classes", placeholder="Classes", elem_id=f"{tab}_detailer_classes") with gr.Row(): - steps = gr.Slider(label="Detailer steps", elem_id=f"{tab}_detailer_steps", value=shared.opts.detailer_steps, min=0, max=99, step=1) - strength = gr.Slider(label="Detailer strength", elem_id=f"{tab}_detailer_strength", value=shared.opts.detailer_strength, minimum=0, maximum=1, step=0.01) + prompt = gr.Textbox(label="Detailer prompt", value='', placeholder='Detailer prompt', lines=2) + with gr.Row(): + negative = gr.Textbox(label="Detailer negative prompt", value='', placeholder='Detailer negative prompt', lines=2) + with gr.Row(): + steps = gr.Slider(label="Detailer steps", elem_id=f"{tab}_detailer_steps", value=10, min=0, max=99, step=1) + strength = gr.Slider(label="Detailer strength", elem_id=f"{tab}_detailer_strength", value=0.3, minimum=0, maximum=1, step=0.01) with gr.Row(): max_detected = gr.Slider(label="Max detected", elem_id=f"{tab}_detailer_max", value=shared.opts.detailer_max, min=1, maximum=10, step=1) with gr.Row(): @@ -347,7 +349,6 @@ class YoloRestorer(Detailer): max_size = gr.Slider(label="Max size", elem_id=f"{tab}_detailer_max_size", value=max_size, minimum=0.0, maximum=1.0, step=0.05) detailers.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) classes.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) - strength.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) padding.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) blur.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) min_confidence.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) @@ -355,8 +356,7 @@ class YoloRestorer(Detailer): min_size.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) max_size.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) iou.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) - steps.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps], outputs=[]) - return enabled + return enabled, prompt, negative, steps, strength def initialize(): diff --git a/modules/processing.py b/modules/processing.py index c2221823e..99fb9f7f3 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -53,8 +53,8 @@ class Processed: self.batch_size = max(1, p.batch_size) self.restore_faces = p.restore_faces or False self.face_restoration_model = shared.opts.face_restoration_model if p.restore_faces else None - self.detailer = p.detailer or False - self.detailer_model = shared.opts.detailer_model if p.detailer else None + self.detailer = p.detailer_enabled or False + self.detailer_model = shared.opts.detailer_model if p.detailer_enabled else None self.sd_model_hash = getattr(shared.sd_model, 'sd_model_hash', '') if model_data.sd_model is not None else '' self.seed_resize_from_w = p.seed_resize_from_w self.seed_resize_from_h = p.seed_resize_from_h @@ -374,7 +374,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: sample = face_restoration.restore_faces(sample, p) if sample is not None: image = Image.fromarray(sample) - if p.detailer: + if p.detailer_enabled: p.ops.append('detailer') if not p.do_not_save_samples and shared.opts.save_images_before_detailer: info = create_infotext(p, p.prompts, p.seeds, p.subseeds, index=i) diff --git a/modules/processing_args.py b/modules/processing_args.py index 7b27e8c31..2bc1c1ce2 100644 --- a/modules/processing_args.py +++ b/modules/processing_args.py @@ -65,7 +65,7 @@ def task_specific_kwargs(p, model): elif (sd_models.get_diffusers_task(model) == sd_models.DiffusersTaskType.INPAINTING or is_img2img_model) and len(getattr(p, 'init_images', [])) > 0: if shared.sd_model_type == 'sdxl' and hasattr(model, 'register_to_config'): model.register_to_config(requires_aesthetics_score = False) - if p.detailer: + if p.detailer_enabled: p.ops.append('detailer') else: p.ops.append('inpaint') diff --git a/modules/processing_class.py b/modules/processing_class.py index 60aa52c50..3eeb73622 100644 --- a/modules/processing_class.py +++ b/modules/processing_class.py @@ -52,8 +52,13 @@ class StableDiffusionProcessing: # other hidiffusion: bool = False, do_not_reload_embeddings: bool = False, - detailer: bool = False, restore_faces: bool = False, + # detailer + detailer_enabled: bool = False, + detailer_prompt: str = '', + detailer_negative: str = '', + detailer_steps: int = 10, + detailer_strength: float = 0.3, # hdr corrections hdr_mode: int = 0, hdr_brightness: float = 0, @@ -167,7 +172,11 @@ class StableDiffusionProcessing: self.full_quality = full_quality self.hidiffusion = hidiffusion self.do_not_reload_embeddings = do_not_reload_embeddings - self.detailer = detailer + self.detailer_enabled = detailer_enabled + self.detailer_prompt = detailer_prompt + self.detailer_negative = detailer_negative + self.detailer_steps = detailer_steps + self.detailer_strength = detailer_strength self.restore_faces = restore_faces self.init_images = init_images self.resize_mode = resize_mode diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index 2ad1df4b8..a21712fae 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -47,7 +47,7 @@ def restore_state(p: processing.StableDiffusionProcessing): p.init_images = None if state == 'reprocess_detail': p.skip = ['encode', 'base', 'hires'] - p.detailer = True + p.detailer_enabled = True shared.log.info(f'Restore state: op={p.state} skip={p.skip}') return p diff --git a/modules/processing_helpers.py b/modules/processing_helpers.py index fe6fa3b3c..e4a35442b 100644 --- a/modules/processing_helpers.py +++ b/modules/processing_helpers.py @@ -601,7 +601,7 @@ def get_job_name(p, model): else: return 'Image' elif sd_models.get_diffusers_task(model) == sd_models.DiffusersTaskType.INPAINTING: - if p.detailer: + if p.detailer_enabled: return 'Detailer' else: return 'Inpaint' diff --git a/modules/processing_info.py b/modules/processing_info.py index 54bfe331d..f3c8eea81 100644 --- a/modules/processing_info.py +++ b/modules/processing_info.py @@ -52,8 +52,8 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No "Model": None if (not shared.opts.add_model_name_to_info) or (not shared.sd_model.sd_checkpoint_info.model_name) else shared.sd_model.sd_checkpoint_info.model_name.replace(',', '').replace(':', ''), "Model hash": getattr(p, 'sd_model_hash', None if (not shared.opts.add_model_hash_to_info) or (not shared.sd_model.sd_model_hash) else shared.sd_model.sd_model_hash), "VAE": (None if not shared.opts.add_model_name_to_info or sd_vae.loaded_vae_file is None else os.path.splitext(os.path.basename(sd_vae.loaded_vae_file))[0]) if p.full_quality else 'TAESD', - "Prompt2": p.refiner_prompt if len(p.refiner_prompt) > 0 else None, - "Negative2": p.refiner_negative if len(p.refiner_negative) > 0 else None, + "Refiner prompt": p.refiner_prompt if len(p.refiner_prompt) > 0 else None, + "Refiner negative": p.refiner_negative if len(p.refiner_negative) > 0 else None, "Styles": "; ".join(p.styles) if p.styles is not None and len(p.styles) > 0 else None, # sdnext "App": 'SD.Next', @@ -136,6 +136,10 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No args['Size name mask'] = p.resize_name_mask if 'detailer' in p.ops: args["Detailer"] = ', '.join(shared.opts.detailer_models) + args["Detailer steps"] = p.detailer_steps + args["Detailer strength"] = p.detailer_strength + args["Detailer prompt"] = p.detailer_prompt if len(p.detailer_prompt) > 0 else None + args["Detailer negative"] = p.detailer_negative if len(p.detailer_negative) > 0 else None if 'color' in p.ops: args["Color correction"] = True # embeddings diff --git a/modules/processing_original.py b/modules/processing_original.py index 649023aae..5ea255d72 100644 --- a/modules/processing_original.py +++ b/modules/processing_original.py @@ -90,11 +90,11 @@ def sample_txt2img(p: processing.StableDiffusionProcessingTxt2Img, conditioning, for i, x_sample in enumerate(decoded_samples): x_sample = validate_sample(x_sample) image = Image.fromarray(x_sample) - bak_extra_generation_params, bak_detailer = p.extra_generation_params, p.detailer + orig_extra_generation_params, orig_detailer = p.extra_generation_params, p.detailer_denabled p.extra_generation_params = {} - p.detailer = False + p.detailer_denabled = False info = processing.create_infotext(p, p.all_prompts, p.all_seeds, p.all_subseeds, [], iteration=p.iteration, position_in_batch=i) - p.extra_generation_params, p.detailer = bak_extra_generation_params, bak_detailer + p.extra_generation_params, p.detailer_enabled = orig_extra_generation_params, orig_detailer images.save_image(image, p.outpath_samples, "", seeds[i], prompts[i], shared.opts.samples_format, info=info, suffix="-before-hires") if latent_scale_mode is None or p.hr_force: # non-latent upscaling shared.state.job = 'Upscale' diff --git a/modules/shared.py b/modules/shared.py index 699585f27..3e1f50607 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -865,8 +865,6 @@ options_templates.update(options_section(('postprocessing', "Postprocessing"), { "detailer_max_size": OptionInfo(1.0, "Max object size", gr.Slider, {"minimum": 0.1, "maximum": 1, "step": 0.05, "visible": False}), "detailer_padding": OptionInfo(20, "Item padding", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1, "visible": False}), "detailer_blur": OptionInfo(10, "Item edge blur", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1, "visible": False}), - "detailer_steps": OptionInfo(10, "Detailer steps", gr.Slider, {"minimum": 0, "maximum": 99, "step": 1, "visible": False}), - "detailer_strength": OptionInfo(0.5, "Detailer strength", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01, "visible": False}), "detailer_models": OptionInfo(['face-yolo8n'], "Detailer models", gr.Dropdown, lambda: {"multiselect":True, "choices": list(yolo.list), "visible": False}), "detailer_unload": OptionInfo(False, "Move detailer model to CPU when complete"), "detailer_augment": OptionInfo(True, "Detailer use model augment"), diff --git a/modules/txt2img.py b/modules/txt2img.py index e82c744a2..e2cf7af77 100644 --- a/modules/txt2img.py +++ b/modules/txt2img.py @@ -11,7 +11,8 @@ debug('Trace: PROCESS') def txt2img(id_task, state, prompt, negative_prompt, prompt_styles, steps, sampler_index, hr_sampler_index, - full_quality, detailer, tiling, hidiffusion, + full_quality, tiling, hidiffusion, + detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, n_iter, batch_size, cfg_scale, image_cfg_scale, diffusers_guidance_rescale, pag_scale, pag_adaptive, cfg_end, clip_skip, @@ -24,7 +25,7 @@ def txt2img(id_task, state, override_settings_texts, *args): - debug(f'txt2img: id_task={id_task}|prompt={prompt}|negative={negative_prompt}|styles={prompt_styles}|steps={steps}|sampler_index={sampler_index}|hr_sampler_index={hr_sampler_index}|full_quality={full_quality}|detailer={detailer}|tiling={tiling}|hidiffusion={hidiffusion}|batch_count={n_iter}|batch_size={batch_size}|cfg_scale={cfg_scale}|clip_skip={clip_skip}|seed={seed}|subseed={subseed}|subseed_strength={subseed_strength}|seed_resize_from_h={seed_resize_from_h}|seed_resize_from_w={seed_resize_from_w}|height={height}|width={width}|enable_hr={enable_hr}|denoising_strength={denoising_strength}|hr_resize_mode={hr_resize_mode}|hr_resize_context={hr_resize_context}|hr_scale={hr_scale}|hr_upscaler={hr_upscaler}|hr_force={hr_force}|hr_second_pass_steps={hr_second_pass_steps}|hr_resize_x={hr_resize_x}|hr_resize_y={hr_resize_y}|image_cfg_scale={image_cfg_scale}|diffusers_guidance_rescale={diffusers_guidance_rescale}|refiner_steps={refiner_steps}|refiner_start={refiner_start}|refiner_prompt={refiner_prompt}|refiner_negative={refiner_negative}|override_settings={override_settings_texts}') + debug(f'txt2img: {id_task}') if shared.sd_model is None: shared.log.warning('Aborted: op=txt model not loaded') @@ -64,7 +65,11 @@ def txt2img(id_task, state, width=width, height=height, full_quality=full_quality, - detailer=detailer, + detailer_enabled=detailer_enabled, + detailer_prompt=detailer_prompt, + detailer_negative=detailer_negative, + detailer_steps=detailer_steps, + detailer_strength=detailer_strength, tiling=tiling, hidiffusion=hidiffusion, enable_hr=enable_hr, diff --git a/modules/ui_control.py b/modules/ui_control.py index a18d2305c..952b956f8 100644 --- a/modules/ui_control.py +++ b/modules/ui_control.py @@ -177,7 +177,7 @@ def create_ui(_blocks: gr.Blocks=None): video_type.change(fn=helpers.video_type_change, inputs=[video_type], outputs=[video_duration, video_loop, video_pad, video_interpolate]) enable_hr, hr_sampler_index, hr_denoising_strength, hr_resize_mode, hr_resize_context, hr_upscaler, hr_force, hr_second_pass_steps, hr_scale, hr_resize_x, hr_resize_y, refiner_steps, refiner_start, refiner_prompt, refiner_negative = ui_sections.create_hires_inputs('control') - detailer = shared.yolo.ui('control') + detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength = shared.yolo.ui('control') with gr.Row(): override_settings = ui_common.create_override_inputs('control') @@ -567,7 +567,8 @@ def create_ui(_blocks: gr.Blocks=None): prompt, negative, styles, steps, sampler_index, seed, subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, - cfg_scale, clip_skip, image_cfg_scale, guidance_rescale, pag_scale, pag_adaptive, cfg_end, full_quality, detailer, tiling, hidiffusion, + cfg_scale, clip_skip, image_cfg_scale, guidance_rescale, pag_scale, pag_adaptive, cfg_end, full_quality, tiling, hidiffusion, + detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundry, hdr_color_picker, hdr_tint_ratio, resize_mode_before, resize_name_before, resize_context_before, width_before, height_before, scale_by_before, selected_scale_tab_before, resize_mode_after, resize_name_after, resize_context_after, width_after, height_after, scale_by_after, selected_scale_tab_after, @@ -652,9 +653,14 @@ def create_ui(_blocks: gr.Blocks=None): (image_cfg_scale, "Hires CFG scale"), (guidance_rescale, "CFG rescale"), (full_quality, "Full quality"), - (detailer, "Detailer"), (tiling, "Tiling"), (hidiffusion, "HiDiffusion"), + # detailer + (detailer_enabled, "Detailer"), + (detailer_prompt, "Detailer prompt"), + (detailer_negative, "Detailer negative"), + (detailer_steps, "Detailer steps"), + (detailer_strength, "Detailer strength"), # second pass (enable_hr, "Second pass"), (enable_hr, "Refine"), @@ -673,8 +679,8 @@ def create_ui(_blocks: gr.Blocks=None): # refiner (refiner_start, "Refiner start"), (refiner_steps, "Refiner steps"), - (refiner_prompt, "Prompt2"), - (refiner_negative, "Negative2"), + (refiner_prompt, "refiner prompt"), + (refiner_negative, "Refiner negative"), # pag (pag_scale, "PAG scale"), (pag_adaptive, "PAG adaptive"), diff --git a/modules/ui_img2img.py b/modules/ui_img2img.py index 74bfd0519..0b59e1b09 100644 --- a/modules/ui_img2img.py +++ b/modules/ui_img2img.py @@ -133,7 +133,7 @@ def create_ui(): full_quality, tiling, hidiffusion, cfg_scale, clip_skip, image_cfg_scale, diffusers_guidance_rescale, pag_scale, pag_adaptive, cfg_end = ui_sections.create_advanced_inputs('img2img') hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundry, hdr_color_picker, hdr_tint_ratio = ui_sections.create_correction_inputs('img2img') enable_hr, hr_sampler_index, hr_denoising_strength, hr_resize_mode, hr_resize_context, hr_upscaler, hr_force, hr_second_pass_steps, hr_scale, hr_resize_x, hr_resize_y, refiner_steps, hr_refiner_start, refiner_prompt, refiner_negative = ui_sections.create_hires_inputs('txt2img') - detailer = shared.yolo.ui('img2img') + detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength = shared.yolo.ui('img2img') # with gr.Group(elem_id="inpaint_controls", visible=False) as inpaint_controls: with gr.Accordion(open=False, label="Mask", elem_classes=["small-accordion"], elem_id="img2img_mask_group") as inpaint_controls: @@ -174,7 +174,8 @@ def create_ui(): sampler_index, mask_blur, mask_alpha, inpainting_fill, - full_quality, detailer, tiling, hidiffusion, + full_quality, tiling, hidiffusion, + detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, batch_count, batch_size, cfg_scale, image_cfg_scale, diffusers_guidance_rescale, pag_scale, pag_adaptive, cfg_end, @@ -261,9 +262,14 @@ def create_ui(): (clip_skip, "Clip skip"), (diffusers_guidance_rescale, "CFG rescale"), (full_quality, "Full quality"), - (detailer, "Detailer"), (tiling, "Tiling"), (hidiffusion, "HiDiffusion"), + # detailer + (detailer_enabled, "Detailer"), + (detailer_prompt, "Detailer prompt"), + (detailer_negative, "Detailer negative"), + (detailer_steps, "Detailer steps"), + (detailer_strength, "Detailer strength"), # second pass (enable_hr, "Second pass"), (enable_hr, "Refine"), @@ -282,8 +288,8 @@ def create_ui(): # refiner (refiner_start, "Refiner start"), (refiner_steps, "Refiner steps"), - (refiner_prompt, "Prompt2"), - (refiner_negative, "Negative2"), + (refiner_prompt, "refiner prompt"), + (refiner_negative, "Refiner negative"), # pag (pag_scale, "PAG scale"), (pag_adaptive, "PAG adaptive"), diff --git a/modules/ui_sections.py b/modules/ui_sections.py index 839fa9025..346c53783 100644 --- a/modules/ui_sections.py +++ b/modules/ui_sections.py @@ -63,21 +63,6 @@ def create_toprow(is_img2img: bool = False, id_part: str = None): def ar_change(ar, width, height): - """ - if ar == 'AR': - return gr.update(interactive=True), gr.update(interactive=True) - try: - (w, h) = [float(x) for x in ar.split(':')] - except Exception as e: - shared.log.warning(f"Invalid aspect ratio: {ar} {e}") - return gr.update(interactive=True), gr.update(interactive=True) - if w > h: - return gr.update(interactive=True, value=width), gr.update(interactive=False, value=int(width * h / w)) - elif w < h: - return gr.update(interactive=False, value=int(height * w / h)), gr.update(interactive=True, value=height) - else: - return gr.update(interactive=True, value=width), gr.update(interactive=False, value=width) - """ if ar == 'AR': return gr.update(), gr.update() try: diff --git a/modules/ui_txt2img.py b/modules/ui_txt2img.py index 9fc69a4db..64d2906f8 100644 --- a/modules/ui_txt2img.py +++ b/modules/ui_txt2img.py @@ -47,7 +47,7 @@ def create_ui(): full_quality, tiling, hidiffusion, _cfg_scale, clip_skip, image_cfg_scale, diffusers_guidance_rescale, pag_scale, pag_adaptive, _cfg_end = ui_sections.create_advanced_inputs('txt2img', base=False) hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundry, hdr_color_picker, hdr_tint_ratio = ui_sections.create_correction_inputs('txt2img') enable_hr, hr_sampler_index, denoising_strength, hr_resize_mode, hr_resize_context, hr_upscaler, hr_force, hr_second_pass_steps, hr_scale, hr_resize_x, hr_resize_y, refiner_steps, refiner_start, refiner_prompt, refiner_negative = ui_sections.create_hires_inputs('txt2img') - detailer = shared.yolo.ui('txt2img') + detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength = shared.yolo.ui('txt2img') override_settings = ui_common.create_override_inputs('txt2img') state = gr.Textbox(value='', visible=False) @@ -64,7 +64,8 @@ def create_ui(): dummy_component, state, txt2img_prompt, txt2img_negative_prompt, txt2img_prompt_styles, steps, sampler_index, hr_sampler_index, - full_quality, detailer, tiling, hidiffusion, + full_quality, tiling, hidiffusion, + detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, batch_count, batch_size, cfg_scale, image_cfg_scale, diffusers_guidance_rescale, pag_scale, pag_adaptive, cfg_end, clip_skip, @@ -122,9 +123,14 @@ def create_ui(): (image_cfg_scale, "Hires CFG scale"), (diffusers_guidance_rescale, "CFG rescale"), (full_quality, "Full quality"), - (detailer, "Detailer"), (tiling, "Tiling"), (hidiffusion, "HiDiffusion"), + # detailer + (detailer_enabled, "Detailer"), + (detailer_prompt, "Detailer prompt"), + (detailer_negative, "Detailer negative"), + (detailer_steps, "Detailer steps"), + (detailer_strength, "Detailer strength"), # second pass (enable_hr, "Second pass"), (enable_hr, "Refine"), @@ -143,8 +149,8 @@ def create_ui(): # refiner (refiner_start, "Refiner start"), (refiner_steps, "Refiner steps"), - (refiner_prompt, "Prompt2"), - (refiner_negative, "Negative2"), + (refiner_prompt, "refiner prompt"), + (refiner_negative, "Refiner negative"), # pag (pag_scale, "PAG scale"), (pag_adaptive, "PAG adaptive"), diff --git a/scripts/xyz_grid_classes.py b/scripts/xyz_grid_classes.py index cc70d68f8..2b1fa2d59 100644 --- a/scripts/xyz_grid_classes.py +++ b/scripts/xyz_grid_classes.py @@ -1,4 +1,4 @@ -from scripts.xyz_grid_shared import apply_field, apply_task_args, apply_setting, apply_prompt, apply_order, apply_sampler, apply_hr_sampler_name, confirm_samplers, apply_checkpoint, apply_refiner, apply_unet, apply_dict, apply_clip_skip, apply_vae, list_lora, apply_lora, apply_lora_strength, apply_te, apply_styles, apply_upscaler, apply_context, apply_detailer, apply_override, apply_processing, apply_options, apply_seed, format_value_add_label, format_value, format_value_join_list, do_nothing, format_nothing, str_permutations # pylint: disable=no-name-in-module, unused-import +from scripts.xyz_grid_shared import apply_field, apply_task_args, apply_setting, apply_prompt_primary, apply_prompt_refine, apply_prompt_detailer, apply_prompt_all, apply_order, apply_sampler, apply_hr_sampler_name, confirm_samplers, apply_checkpoint, apply_refiner, apply_unet, apply_dict, apply_clip_skip, apply_vae, list_lora, apply_lora, apply_lora_strength, apply_te, apply_styles, apply_upscaler, apply_context, apply_detailer, apply_override, apply_processing, apply_options, apply_seed, format_value_add_label, format_value, format_value_join_list, do_nothing, format_nothing, str_permutations # pylint: disable=no-name-in-module, unused-import from modules import shared, shared_items, sd_samplers, ipadapter, sd_models, sd_vae, sd_unet @@ -93,7 +93,10 @@ axis_options = [ AxisOption("[Model] Refiner", str, apply_refiner, cost=0.8, fmt=format_value_add_label, choices=lambda: ['None'] + sorted(sd_models.checkpoints_list)), AxisOption("[Model] Text encoder", str, apply_te, cost=0.7, choices=shared_items.sd_te_items), AxisOption("[Model] Dictionary", str, apply_dict, fmt=format_value_add_label, cost=0.9, choices=lambda: ['None'] + list(sd_models.checkpoints_list)), - AxisOption("[Prompt] Search & replace", str, apply_prompt, fmt=format_value_add_label), + AxisOption("[Prompt] Search & replace", str, apply_prompt_primary, fmt=format_value_add_label), + AxisOption("[Prompt] Search & replace refine", str, apply_prompt_refine, fmt=format_value_add_label), + AxisOption("[Prompt] Search & replace detailer", str, apply_prompt_detailer, fmt=format_value_add_label), + AxisOption("[Prompt] Search & replace all", str, apply_prompt_all, fmt=format_value_add_label), AxisOption("[Prompt] Prompt order", str_permutations, apply_order, fmt=format_value_join_list), AxisOption("[Prompt] Prompt parser", str, apply_setting("prompt_attention"), choices=lambda: ["native", "compel", "xhinker", "a1111", "fixed"]), AxisOption("[Network] LoRA", str, apply_lora, cost=0.5, choices=list_lora), diff --git a/scripts/xyz_grid_on.py b/scripts/xyz_grid_on.py index 5c5ef8bf5..5e03e1c5c 100644 --- a/scripts/xyz_grid_on.py +++ b/scripts/xyz_grid_on.py @@ -286,8 +286,8 @@ class Script(scripts.Script): total_steps += p.hr_second_pass_steps * total_jobs else: total_steps *= 2 - if p.detailer: - total_steps += shared.opts.detailer_steps * total_jobs + if p.detailer_enabled: + total_steps += p.detailer_steps * total_jobs total_steps *= p.n_iter total_jobs *= p.n_iter @@ -432,7 +432,7 @@ class Script(scripts.Script): def process_images(self, p, *args): # pylint: disable=W0221, W0613 if xyz_results_cache is not None and len(xyz_results_cache.images) > 0: p.restore_faces = False - p.detailer = False + p.detailer_enabled = False p.color_corrections = None # p.scripts = None return xyz_results_cache diff --git a/scripts/xyz_grid_shared.py b/scripts/xyz_grid_shared.py index f9bf26c67..efd70724b 100644 --- a/scripts/xyz_grid_shared.py +++ b/scripts/xyz_grid_shared.py @@ -62,18 +62,37 @@ def apply_seed(p, x, xs): shared.log.debug(f'XYZ grid apply seed: {x}') -def apply_prompt(p, x, xs): +def apply_prompt(positive, negative, p, x, xs): for s in xs: - if s in p.prompt: - shared.log.debug(f'XYZ grid apply prompt: "{s}"="{x}"') - p.prompt = p.prompt.replace(s, x) - if s in p.negative_prompt: - shared.log.debug(f'XYZ grid apply negative: "{s}"="{x}"') - p.negative_prompt = p.negative_prompt.replace(s, x) + shared.log.debug(f'XYZ grid apply prompt: fields={positive}/{negative} "{s}"="{x}"') + orig_positive = getattr(p, positive) + orig_negative = getattr(p, negative) + if s in orig_positive: + setattr(p, positive, orig_positive.replace(s, x)) + if s in orig_negative: + setattr(p, negative, orig_negative.replace(s, x)) + + +def apply_prompt_primary(p, x, xs): + apply_prompt('prompt', 'negative_prompt', p, x, xs) p.all_prompts = None p.all_negative_prompts = None +def apply_prompt_refine(p, x, xs): + apply_prompt('refiner_prompt', 'refiner_negative', p, x, xs) + + +def apply_prompt_detailer(p, x, xs): + apply_prompt('detailer_prompt', 'detailer_negative', p, x, xs) + + +def apply_prompt_all(p, x, xs): + apply_prompt('prompt', 'negative_prompt', p, x, xs) + apply_prompt('refiner_prompt', 'refiner_negative', p, x, xs) + apply_prompt('detailer_prompt', 'detailer_negative', p, x, xs) + + def apply_order(p, x, xs): token_order = [] for token in x: @@ -251,7 +270,7 @@ def apply_detailer(p, opt, x): p.detailer_model = 'GFPGAN' else: is_active = opt in ('true', 'yes', 'y', '1') - p.detailer = is_active + p.detailer_enabled = is_active shared.log.debug(f'XYZ grid apply face-restore: "{x}"') diff --git a/wiki b/wiki index a0c9483d8..7793288e3 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit a0c9483d8a1a979911b056f86afa598fca635857 +Subproject commit 7793288e3ac320f48c728cbee67cd34683c0fa81