diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fc27ab65..31f604f6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log for SD.Next +## Known issues + +- z-image-turbo controlnet device mismatch: +- z-image-turbo safetensors loader: +- kandinsky-image-5 hardcoded cuda: + ## Update for 2025-12-24 - **Models** @@ -13,10 +19,10 @@ - **Features** - Google **Gemini** and **Veo** models support for both *Dev* and *Vertex* access methods see [docs](https://vladmandic.github.io/sdnext-docs/Google-GenAI/) for details - - **Z-Image** support loading transformer file-tunes in safetensors format + - **Z-Image Turbo** support loading transformer file-tunes in safetensors format as with any transformers/unet finetunes, place them then `models/unet` and use **UNET Model** to load safetensors file as they are not complete models - - **Z-Image** support for **ControlNet Union** + - **Z-Image Turbo** support for **ControlNet Union** includes 1.0, 2.0 and 2.1 variants - **Detailer** support for segmentation models some detection models can produce exact segmentation mask and not just box diff --git a/modules/control/run.py b/modules/control/run.py index 6d02d1ed4..726d3aa4f 100644 --- a/modules/control/run.py +++ b/modules/control/run.py @@ -182,7 +182,7 @@ def check_active(p, unit_type, units): p.is_tile = p.is_tile or 'tile' in u.mode.lower() p.control_tile = u.tile p.extra_generation_params["Control mode"] = u.mode - shared.log.debug(f'Control ControlNet unit: i={num_units} process="{u.process.processor_id}" model="{u.controlnet.model_id}" strength={u.strength} guess={u.guess} start={u.start} end={u.end} mode={u.mode}') + shared.log.debug(f'Control unit: i={num_units} type=ControlNet process="{u.process.processor_id}" model="{u.controlnet.model_id}" strength={u.strength} guess={u.guess} start={u.start} end={u.end} mode={u.mode}') elif unit_type == 'xs' and u.controlnet.model is not None: active_process.append(u.process) active_model.append(u.controlnet) @@ -190,13 +190,13 @@ def check_active(p, unit_type, units): active_start.append(float(u.start)) active_end.append(float(u.end)) active_units.append(u) - shared.log.debug(f'Control ControlNet-XS unit: i={num_units} process={u.process.processor_id} model={u.controlnet.model_id} strength={u.strength} guess={u.guess} start={u.start} end={u.end}') + shared.log.debug(f'Control unit: i={num_units} type=ControlNetXS process={u.process.processor_id} model={u.controlnet.model_id} strength={u.strength} guess={u.guess} start={u.start} end={u.end}') elif unit_type == 'lite' and u.controlnet.model is not None: active_process.append(u.process) active_model.append(u.controlnet) active_strength.append(float(u.strength)) active_units.append(u) - shared.log.debug(f'Control ControlLLite unit: i={num_units} process={u.process.processor_id} model={u.controlnet.model_id} strength={u.strength} guess={u.guess} start={u.start} end={u.end}') + shared.log.debug(f'Control unit: i={num_units} type=ControlLLite process={u.process.processor_id} model={u.controlnet.model_id} strength={u.strength} guess={u.guess} start={u.start} end={u.end}') elif unit_type == 'reference': p.override = u.override p.attention = u.attention @@ -209,7 +209,7 @@ def check_active(p, unit_type, units): if u.process.processor_id is not None: active_process.append(u.process) active_units.append(u) - shared.log.debug(f'Control process unit: i={num_units} process={u.process.processor_id}') + shared.log.debug(f'Control unit: i={num_units} type=Process process={u.process.processor_id}') active_strength.append(float(u.strength)) debug_log(f'Control active: process={len(active_process)} model={len(active_model)}') return active_process, active_model, active_strength, active_start, active_end, active_units @@ -654,7 +654,7 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg debug_log(f'Control: pipeline units={len(active_model)} process={len(active_process)} outputs={len(output_images)}') except Exception as e: - shared.log.error(f'Control pipeline failed: type={unit_type} units={len(active_model)} error={e}') + shared.log.error(f'Control: type={unit_type} units={len(active_model)} {e}') errors.display(e, 'Control') if len(output_images) == 0: diff --git a/modules/control/unit.py b/modules/control/unit.py index 5591749de..2eba804af 100644 --- a/modules/control/unit.py +++ b/modules/control/unit.py @@ -134,15 +134,15 @@ class Unit(): # mashup of gradio controls and mapping to actual implementation c if image_file is None: self.process.override = None self.override = None - log.debug('Control process clear image') + log.debug('Control image: clear') return gr.update(value=None) try: self.process.override = Image.open(image_file.name) self.override = self.process.override - log.debug(f'Control process upload image: path="{image_file.name}" image={self.process.override}') + log.debug(f'Control image: upload={self.process.override} path="{image_file.name}"') return gr.update(visible=self.process.override is not None, value=self.process.override) except Exception as e: - log.error(f'Control process upload image failed: path="{image_file.name}" error={e}') + log.error(f'Control image: upload path="{image_file.name}" error={e}') return gr.update(visible=False, value=None) def reuse_image(image): diff --git a/modules/control/units/controlnet.py b/modules/control/units/controlnet.py index 4e1398b12..7727dc476 100644 --- a/modules/control/units/controlnet.py +++ b/modules/control/units/controlnet.py @@ -536,6 +536,7 @@ class ControlNetPipeline(): scheduler=pipeline.scheduler, controlnet=controlnets[0] if isinstance(controlnets, list) else controlnets, # can be a list ) + self.pipeline.task_args['guidance_scale'] = 0 elif len(loras) > 0: self.pipeline = pipeline for lora in loras: diff --git a/modules/processing_args.py b/modules/processing_args.py index 686f024a5..869b1309e 100644 --- a/modules/processing_args.py +++ b/modules/processing_args.py @@ -462,7 +462,7 @@ def set_pipeline_args(p, model, prompts:list, negative_prompts:list, prompts_2:t args['max_area'] = args['width'] * args['height'] # handle implicit controlnet - if 'control_image' in possible and 'control_image' not in args and 'image' in args: + if ('control_image' in possible) and ('control_image' not in args) and ('image' in args): if sd_models.get_diffusers_task(model) != sd_models.DiffusersTaskType.MODULAR: debug_log('Process: set control image') args['control_image'] = args['image'] diff --git a/modules/ui_common.py b/modules/ui_common.py index 57536874a..98cda43d8 100644 --- a/modules/ui_common.py +++ b/modules/ui_common.py @@ -414,7 +414,7 @@ def update_token_counter(text): token_count = 0 max_length = 75 if shared.state.job_count > 0: - shared.log.info('Tokenizer busy') + shared.log.debug('Tokenizer busy') return f"{token_count}/{max_length}" from modules import extra_networks prompt, _ = extra_networks.parse_prompt(text)