mirror of
https://github.com/vladmandic/automatic
synced 2026-09-20 01:31:13 +02:00
Merge branch 'dev' into ipadapter-end
This commit is contained in:
+7
-2
@@ -1,6 +1,6 @@
|
||||
# Change Log for SD.Next
|
||||
|
||||
## Update for 2024-02-10
|
||||
## Update for 2024-02-12
|
||||
|
||||
- **improvements**:
|
||||
- **IP Adapter** major refactor
|
||||
@@ -9,7 +9,7 @@
|
||||
*note*: you cannot mix & match ip adapters that use different *CLiP* models, for example `Base` and `Base ViT-G`
|
||||
- unified interface in txt2img, img2img and control
|
||||
- enhanced xyz grid support
|
||||
- **FaceID** now works with multiple input images
|
||||
- **FaceID** now also works with multiple input images!
|
||||
- **CFG End** new param to control image generation guidance, thanks @AI-Casanova
|
||||
sometimes you want strong control over composition, but you want it to stop at some point
|
||||
for example, when used with ip-adapters or controlnet, high cfg scale can overpower the guided image
|
||||
@@ -55,6 +55,11 @@
|
||||
- lazy loading of image may prevent metadata from being loaded on time
|
||||
- allow startup without valid models folder
|
||||
- fix interrogate api endpoint
|
||||
- control fix resize causing runtime errors
|
||||
- control fix processor override image after processor change
|
||||
- fix vae dtype mismatch, thanks @Disty0
|
||||
- fix controlnet inpaint mask
|
||||
- bind controlnet extension to last known working commit, thanks @Aptronymist
|
||||
- handle extensions that install conflicting versions of packages
|
||||
`onnxruntime`, `opencv2-python`
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@ Main ToDo list can be found at [GitHub projects](https://github.com/users/vladma
|
||||
|
||||
## Candidates for next release
|
||||
|
||||
- diffusers public callbacks
|
||||
- control second pass: <https://github.com/vladmandic/automatic/issues/2783>
|
||||
- onediff: <https://github.com/siliconflow/onediff>
|
||||
- diffusers public callbacks
|
||||
- image2video: pia and vgen pipelines
|
||||
- video2video
|
||||
- control api
|
||||
- masking api
|
||||
- preprocess api
|
||||
- bind panZoom to control input
|
||||
- onediff: <https://github.com/siliconflow/onediff>
|
||||
|
||||
Submodule extensions-builtin/sd-webui-controlnet updated: 416c345072...ecd33eb82b
+5
-8
@@ -47,7 +47,7 @@ args = Dot({
|
||||
})
|
||||
git_commit = "unknown"
|
||||
submodules_commit = {
|
||||
# 'sd-webui-controlnet': 'ecd33eb',
|
||||
'sd-webui-controlnet': 'ecd33eb',
|
||||
# 'stable-diffusion-webui-images-browser': '27fe4a7',
|
||||
}
|
||||
|
||||
@@ -456,12 +456,6 @@ def check_torch():
|
||||
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none')
|
||||
if rocm_ver is not None:
|
||||
install(os.environ.get('ONNXRUNTIME_PACKAGE', get_onnxruntime_source_for_rocm(arr)), "onnxruntime-training built with ROCm", ignore=True)
|
||||
try:
|
||||
import onnxruntime
|
||||
if "ROCMExecutionProvider" not in onnxruntime.get_available_providers():
|
||||
log.warning('Failed to automatically install onxnruntime package for ROCm. Please manually install it if you need.')
|
||||
except Exception:
|
||||
pass
|
||||
elif allow_ipex and (args.use_ipex or shutil.which('sycl-ls') is not None or shutil.which('sycl-ls.exe') is not None or os.environ.get('ONEAPI_ROOT') is not None or os.path.exists('/opt/intel/oneapi') or os.path.exists("C:/Program Files (x86)/Intel/oneAPI") or os.path.exists("C:/oneAPI")):
|
||||
args.use_ipex = True # pylint: disable=attribute-defined-outside-init
|
||||
log.info('Intel OneAPI Toolkit detected')
|
||||
@@ -864,7 +858,10 @@ def get_onnxruntime_source_for_rocm(rocm_ver):
|
||||
if rocm_ver is None:
|
||||
command = subprocess.run('hipconfig --version', shell=True, check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
rocm_ver = command.stdout.decode(encoding="utf8", errors="ignore").split('.')
|
||||
return f"https://download.onnxruntime.ai/onnxruntime_training-{ort_version}%2Brocm{rocm_ver[0]}{rocm_ver[1]}-cp{cp_str}-cp{cp_str}-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
|
||||
if "linux" in sys.platform:
|
||||
return f"https://download.onnxruntime.ai/onnxruntime_training-{ort_version}%2Brocm{rocm_ver[0]}{rocm_ver[1]}-cp{cp_str}-cp{cp_str}-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
|
||||
else:
|
||||
return 'onnxruntime-gpu'
|
||||
|
||||
|
||||
# check version of the main repo and optionally upgrade it
|
||||
|
||||
@@ -126,7 +126,7 @@ class Processor():
|
||||
def __init__(self, processor_id: str = None, resize = True):
|
||||
self.model = None
|
||||
self.processor_id = None
|
||||
# self.override = None
|
||||
self.override = None
|
||||
self.resize = resize
|
||||
self.reset()
|
||||
self.config(processor_id)
|
||||
@@ -138,7 +138,7 @@ class Processor():
|
||||
debug(f'Control Processor unloaded: id="{self.processor_id}"')
|
||||
self.model = None
|
||||
self.processor_id = processor_id
|
||||
self.override = None
|
||||
# self.override = None
|
||||
devices.torch_gc()
|
||||
self.load_config = { 'cache_dir': cache_dir }
|
||||
|
||||
@@ -215,8 +215,8 @@ class Processor():
|
||||
if resize_mode != 0 and resize_name != 'None':
|
||||
if scale_tab == 1:
|
||||
width_before, height_before = int(image_input.width * scale_by), int(image_input.height * scale_by)
|
||||
debug(f'Control resize: op=before image={image_input} width={width_before} height={height_before} mode={resize_mode} name={resize_name}')
|
||||
image_input = images.resize_image(resize_mode, image_input, width_before, height_before, resize_name)
|
||||
debug(f'Control resize: op=before image={image_input} width={width_before} height={height_before} mode={resize_mode} name={resize_name}')
|
||||
image_input = images.resize_image(resize_mode, image_input, width_before, height_before, resize_name)
|
||||
image_process = image_input
|
||||
if image_input is None:
|
||||
# log.error('Control Processor: no input')
|
||||
|
||||
@@ -6,7 +6,7 @@ import json
|
||||
from PIL import Image
|
||||
import gradio as gr
|
||||
from modules.paths import data_path
|
||||
from modules import shared, ui_tempdir, script_callbacks, images
|
||||
from modules import shared, gr_tempdir, script_callbacks, images
|
||||
|
||||
|
||||
re_param_code = r'\s*([\w ]+):\s*("(?:\\"[^,]|\\"|\\|[^\"])+"|[^,]*)(?:,|$)'
|
||||
@@ -58,7 +58,7 @@ def image_from_url_text(filedata):
|
||||
filedata = filedata[0]
|
||||
if type(filedata) == dict and filedata.get("is_file", False):
|
||||
filename = filedata["name"]
|
||||
is_in_right_dir = ui_tempdir.check_tmp_file(shared.demo, filename)
|
||||
is_in_right_dir = gr_tempdir.check_tmp_file(shared.demo, filename)
|
||||
if is_in_right_dir:
|
||||
filename = filename.rsplit('?', 1)[0]
|
||||
if not os.path.exists(filename):
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
from PIL import Image
|
||||
import gradio as gr
|
||||
import gradio.processing_utils
|
||||
from modules import scripts, patches, gr_tempdir
|
||||
|
||||
|
||||
original_IOComponent_init = None
|
||||
original_Block_get_config = None
|
||||
original_BlockContext_init = None
|
||||
original_Blocks_get_config_file = None
|
||||
|
||||
|
||||
def gr_image_preprocess(self, x):
|
||||
@@ -25,5 +32,62 @@ def gr_image_preprocess(self, x):
|
||||
return self._format_image(im) # pylint: disable=protected-access
|
||||
|
||||
|
||||
def add_classes_to_gradio_component(comp):
|
||||
"""
|
||||
this adds gradio-* to the component for css styling (ie gradio-button to gr.Button), as well as some others
|
||||
"""
|
||||
comp.elem_classes = [f"gradio-{comp.get_block_name()}", *(comp.elem_classes or [])]
|
||||
if getattr(comp, 'multiselect', False):
|
||||
comp.elem_classes.append('multiselect')
|
||||
|
||||
|
||||
def IOComponent_init(self, *args, **kwargs):
|
||||
self.webui_tooltip = kwargs.pop('tooltip', None)
|
||||
if scripts.scripts_current is not None:
|
||||
scripts.scripts_current.before_component(self, **kwargs)
|
||||
scripts.script_callbacks.before_component_callback(self, **kwargs)
|
||||
res = original_IOComponent_init(self, *args, **kwargs) # pylint: disable=assignment-from-no-return
|
||||
add_classes_to_gradio_component(self)
|
||||
scripts.script_callbacks.after_component_callback(self, **kwargs)
|
||||
if scripts.scripts_current is not None:
|
||||
scripts.scripts_current.after_component(self, **kwargs)
|
||||
return res
|
||||
|
||||
|
||||
def Block_get_config(self):
|
||||
config = original_Block_get_config(self)
|
||||
webui_tooltip = getattr(self, 'webui_tooltip', None)
|
||||
if webui_tooltip:
|
||||
config["webui_tooltip"] = webui_tooltip
|
||||
config.pop('example_inputs', None)
|
||||
return config
|
||||
|
||||
|
||||
def BlockContext_init(self, *args, **kwargs):
|
||||
if scripts.scripts_current is not None:
|
||||
scripts.scripts_current.before_component(self, **kwargs)
|
||||
scripts.script_callbacks.before_component_callback(self, **kwargs)
|
||||
res = original_BlockContext_init(self, *args, **kwargs) # pylint: disable=assignment-from-no-return
|
||||
add_classes_to_gradio_component(self)
|
||||
scripts.script_callbacks.after_component_callback(self, **kwargs)
|
||||
if scripts.scripts_current is not None:
|
||||
scripts.scripts_current.after_component(self, **kwargs)
|
||||
return res
|
||||
|
||||
|
||||
def Blocks_get_config_file(self, *args, **kwargs):
|
||||
config = original_Blocks_get_config_file(self, *args, **kwargs)
|
||||
for comp_config in config["components"]:
|
||||
if "example_inputs" in comp_config:
|
||||
comp_config["example_inputs"] = {"serialized": []}
|
||||
return config
|
||||
|
||||
|
||||
def init():
|
||||
global original_IOComponent_init, original_Block_get_config, original_BlockContext_init, original_Blocks_get_config_file # pylint: disable=global-statement
|
||||
gr.components.Image.preprocess = gr_image_preprocess
|
||||
gr.components.IOComponent.pil_to_temp_file = gr_tempdir.pil_to_temp_file
|
||||
original_IOComponent_init = patches.patch(__name__, obj=gr.components.IOComponent, field="__init__", replacement=IOComponent_init)
|
||||
original_Block_get_config = patches.patch(__name__, obj=gr.blocks.Block, field="get_config", replacement=Block_get_config)
|
||||
original_BlockContext_init = patches.patch(__name__, obj=gr.blocks.BlockContext, field="__init__", replacement=BlockContext_init)
|
||||
original_Blocks_get_config_file = patches.patch(__name__, obj=gr.blocks.Blocks, field="get_config_file", replacement=Blocks_get_config_file)
|
||||
|
||||
@@ -2,7 +2,6 @@ import os
|
||||
import tempfile
|
||||
from collections import namedtuple
|
||||
from pathlib import Path
|
||||
import gradio as gr
|
||||
from PIL import Image, PngImagePlugin
|
||||
from modules import shared, errors, paths
|
||||
|
||||
@@ -79,7 +78,6 @@ def pil_to_temp_file(self, img: Image, dir: str, format="png") -> str: # pylint:
|
||||
|
||||
|
||||
# override save to file function so that it also writes PNG info
|
||||
gr.components.IOComponent.pil_to_temp_file = pil_to_temp_file # gradio >=3.32.0
|
||||
|
||||
def on_tmpdir_changed():
|
||||
if shared.opts.temp_dir == "":
|
||||
+27
-9
@@ -12,6 +12,10 @@ from modules import shared, errors, devices, ui_components, ui_symbols, paths
|
||||
from modules.memstats import memory_stats
|
||||
|
||||
|
||||
debug = shared.log.trace if os.environ.get('SD_MASK_DEBUG', None) is not None else lambda *args, **kwargs: None
|
||||
debug('Trace: MASK')
|
||||
|
||||
|
||||
def get_crop_region(mask, pad=0):
|
||||
"""finds a rectangular region that contains all masked ares in an image. Returns (x1, y1, x2, y2) coordinates of the rectangle.
|
||||
For example, if a user has painted the top-right part of a 512x512 image", the result may be (256, 0, 512, 256)"""
|
||||
@@ -36,12 +40,22 @@ def get_crop_region(mask, pad=0):
|
||||
if not (mask[i] == 0).all():
|
||||
break
|
||||
crop_bottom += 1
|
||||
return (
|
||||
int(max(crop_left-pad, 0)),
|
||||
int(max(crop_top-pad, 0)),
|
||||
int(min(w - crop_right + pad, w)),
|
||||
int(min(h - crop_bottom + pad, h))
|
||||
x1 = max(crop_left - pad, 0)
|
||||
y1 = max(crop_top - pad, 0)
|
||||
x2 = max(w - crop_right + pad, 0)
|
||||
y2 = max(h - crop_bottom + pad, 0)
|
||||
if x2 < x1:
|
||||
x1, x2 = x2, x1
|
||||
if y2 < y1:
|
||||
y1, y2 = y2, y1
|
||||
crop_region = (
|
||||
int(min(x1, w)),
|
||||
int(min(y1, h)),
|
||||
int(min(x2, w)),
|
||||
int(min(y2, h)),
|
||||
)
|
||||
debug(f'Mask crop: mask={mask.shape} region={crop_region} pad={pad}')
|
||||
return crop_region
|
||||
|
||||
|
||||
def expand_crop_region(crop_region, processing_width, processing_height, image_width, image_height):
|
||||
@@ -79,8 +93,14 @@ def expand_crop_region(crop_region, processing_width, processing_height, image_w
|
||||
x1 -= x1
|
||||
if x2 >= image_width:
|
||||
x2 = image_width
|
||||
|
||||
return x1, y1, x2, y2
|
||||
crop_expand = (
|
||||
int(x1),
|
||||
int(y1),
|
||||
int(x2),
|
||||
int(y2),
|
||||
)
|
||||
debug(f'Mask expand: region={crop_expand} processing={processing_width}x{processing_height} image={image_width}x{image_height}')
|
||||
return crop_expand
|
||||
|
||||
|
||||
def fill(image, mask):
|
||||
@@ -123,8 +143,6 @@ MODELS = {
|
||||
COLORMAP = ['autumn', 'bone', 'jet', 'winter', 'rainbow', 'ocean', 'summer', 'spring', 'cool', 'hsv', 'pink', 'hot', 'parula', 'magma', 'inferno', 'plasma', 'viridis', 'cividis', 'twilight', 'shifted', 'turbo', 'deepgreen']
|
||||
cache_dir = 'models/control/segment'
|
||||
generator: MaskGenerationPipeline = None
|
||||
debug = shared.log.trace if os.environ.get('SD_MASK_DEBUG', None) is not None else lambda *args, **kwargs: None
|
||||
debug('Trace: MASK')
|
||||
busy = False
|
||||
btn_mask = None
|
||||
btn_lama = None
|
||||
|
||||
@@ -44,8 +44,8 @@ def full_vae_decode(latents, model):
|
||||
upcast = (model.vae.dtype == torch.float16) and getattr(model.vae.config, 'force_upcast', False) and hasattr(model, 'upcast_vae')
|
||||
if upcast: # this is done by diffusers automatically if output_type != 'latent'
|
||||
model.upcast_vae()
|
||||
|
||||
latents = latents.to(next(iter(model.vae.post_quant_conv.parameters())).dtype)
|
||||
if hasattr(model.vae, "post_quant_conv"):
|
||||
latents = latents.to(next(iter(model.vae.post_quant_conv.parameters())).dtype)
|
||||
decoded = model.vae.decode(latents / model.vae.config.scaling_factor, return_dict=False)[0]
|
||||
|
||||
# Delete PyTorch VAE after OpenVINO compile
|
||||
|
||||
@@ -9,7 +9,7 @@ import modules.errors as errors
|
||||
|
||||
|
||||
def report_exception(e, c, job):
|
||||
errors.display(e, f'executing callback: {c.script} {job}')
|
||||
errors.display(e, f'Executing callback: {c.script} {job}')
|
||||
|
||||
|
||||
class ImageSaveParams:
|
||||
|
||||
@@ -362,49 +362,6 @@ class ScriptRunner:
|
||||
except Exception as e:
|
||||
errors.log.error(f'Script initialize: {path} {e}')
|
||||
|
||||
"""
|
||||
def create_script_ui(self, script):
|
||||
import modules.api.models as api_models
|
||||
script.args_from = len(self.inputs)
|
||||
script.args_to = len(self.inputs)
|
||||
controls = wrap_call(script.ui, script.filename, "ui", script.is_img2img)
|
||||
if controls is None:
|
||||
return
|
||||
script.name = wrap_call(script.title, script.filename, "title", default=script.filename).lower()
|
||||
api_args = []
|
||||
for control in controls:
|
||||
if not isinstance(control, gr.components.IOComponent):
|
||||
log.error(f'Invalid script control: "{script.filename}" control={control}')
|
||||
continue
|
||||
control.custom_script_source = os.path.basename(script.filename)
|
||||
arg_info = api_models.ScriptArg(label=control.label or "")
|
||||
for field in ("value", "minimum", "maximum", "step", "choices"):
|
||||
v = getattr(control, field, None)
|
||||
if v is not None:
|
||||
setattr(arg_info, field, v)
|
||||
api_args.append(arg_info)
|
||||
script.api_info = api_models.ScriptInfo(name=script.name, is_img2img=script.is_img2img, is_alwayson=script.alwayson, args=api_args)
|
||||
if script.infotext_fields is not None:
|
||||
self.infotext_fields += script.infotext_fields
|
||||
if script.paste_field_names is not None:
|
||||
self.paste_field_names += script.paste_field_names
|
||||
self.inputs += controls
|
||||
script.args_to = len(self.inputs)
|
||||
|
||||
def setup_ui_for_section(self, section, scriptlist=None):
|
||||
if scriptlist is None:
|
||||
scriptlist = self.alwayson_scripts
|
||||
for script in scriptlist:
|
||||
if script.alwayson and script.section != section:
|
||||
continue
|
||||
if script.create_group:
|
||||
with gr.Group(visible=script.alwayson) as group:
|
||||
self.create_script_ui(script)
|
||||
script.group = group
|
||||
else:
|
||||
self.create_script_ui(script)
|
||||
"""
|
||||
|
||||
def prepare_ui(self):
|
||||
self.inputs = [None]
|
||||
|
||||
@@ -677,43 +634,3 @@ def reload_script_body_only():
|
||||
scripts_txt2img.reload_sources(cache)
|
||||
scripts_img2img.reload_sources(cache)
|
||||
scripts_control.reload_sources(cache)
|
||||
|
||||
|
||||
def add_classes_to_gradio_component(comp):
|
||||
"""
|
||||
this adds gradio-* to the component for css styling (ie gradio-button to gr.Button), as well as some others
|
||||
"""
|
||||
elem_classes = []
|
||||
if hasattr(comp, "elem_classes"):
|
||||
elem_classes = comp.elem_classes
|
||||
if elem_classes is None:
|
||||
elem_classes = []
|
||||
comp.elem_classes = [f"gradio-{comp.get_block_name()}", *(comp.elem_classes or [])]
|
||||
if getattr(comp, 'multiselect', False):
|
||||
comp.elem_classes.append('multiselect')
|
||||
|
||||
|
||||
def IOComponent_init(self, *args, **kwargs):
|
||||
if scripts_current is not None:
|
||||
scripts_current.before_component(self, **kwargs)
|
||||
script_callbacks.before_component_callback(self, **kwargs)
|
||||
res = original_IOComponent_init(self, *args, **kwargs) # pylint: disable=assignment-from-no-return
|
||||
add_classes_to_gradio_component(self)
|
||||
script_callbacks.after_component_callback(self, **kwargs)
|
||||
if scripts_current is not None:
|
||||
scripts_current.after_component(self, **kwargs)
|
||||
return res
|
||||
|
||||
|
||||
original_IOComponent_init = gr.components.IOComponent.__init__
|
||||
gr.components.IOComponent.__init__ = IOComponent_init
|
||||
|
||||
|
||||
def BlockContext_init(self, *args, **kwargs):
|
||||
res = original_BlockContext_init(self, *args, **kwargs) # pylint: disable=assignment-from-no-return
|
||||
add_classes_to_gradio_component(self)
|
||||
return res
|
||||
|
||||
|
||||
original_BlockContext_init = gr.blocks.BlockContext.__init__
|
||||
gr.blocks.BlockContext.__init__ = BlockContext_init
|
||||
|
||||
@@ -68,29 +68,39 @@ def ipex_optimize(sd_model):
|
||||
def nncf_compress_weights(sd_model):
|
||||
try:
|
||||
t0 = time.time()
|
||||
if sd_model.device.type == "meta":
|
||||
shared.log.warning("Compress Weights is not compatible with Sequential CPU offload")
|
||||
return sd_model
|
||||
|
||||
def nncf_compress_model(model):
|
||||
return_device = model.device
|
||||
model = nncf.compress_weights(model.to(devices.device)).to(return_device)
|
||||
devices.torch_gc(force=True)
|
||||
return model
|
||||
|
||||
import nncf
|
||||
shared.compiled_model_state = CompiledModelState()
|
||||
shared.compiled_model_state.is_compiled = True
|
||||
|
||||
if "Model" in shared.opts.nncf_compress_weights:
|
||||
if hasattr(sd_model, 'unet') and hasattr(sd_model.unet, 'config'):
|
||||
sd_model.unet = nncf.compress_weights(sd_model.unet)
|
||||
sd_model.unet = nncf_compress_model(sd_model.unet)
|
||||
elif hasattr(sd_model, 'transformer') and hasattr(sd_model.transformer, 'config'):
|
||||
sd_model.transformer = nncf.compress_weights(sd_model.transformer)
|
||||
sd_model.transformer = nncf_compress_model(sd_model.transformer)
|
||||
else:
|
||||
shared.log.warning('Compress Weights enabled but model has no Unet or Transformer')
|
||||
if "VAE" in shared.opts.nncf_compress_weights:
|
||||
if hasattr(sd_model, 'vae') and hasattr(sd_model.vae, 'decode'):
|
||||
sd_model.vae = nncf.compress_weights(sd_model.vae)
|
||||
sd_model.vae = nncf_compress_model(sd_model.vae)
|
||||
elif hasattr(sd_model, 'movq') and hasattr(sd_model.movq, 'decode'):
|
||||
sd_model.movq = nncf.compress_weights(sd_model.movq)
|
||||
sd_model.movq = nncf_compress_model(sd_model.movq)
|
||||
else:
|
||||
shared.log.warning('Compress VAE Weights enabled but model has no VAE')
|
||||
if "Text Encoder" in shared.opts.nncf_compress_weights:
|
||||
if hasattr(sd_model, 'text_encoder') and hasattr(sd_model.text_encoder, 'config'):
|
||||
sd_model.text_encoder = nncf.compress_weights(sd_model.text_encoder)
|
||||
sd_model.text_encoder = nncf_compress_model(sd_model.text_encoder)
|
||||
if hasattr(sd_model, 'text_encoder_2') and hasattr(sd_model.text_encoder_2, 'config'):
|
||||
sd_model.text_encoder_2 = nncf.compress_weights(sd_model.text_encoder_2)
|
||||
sd_model.text_encoder_2 = nncf_compress_model(sd_model.text_encoder_2)
|
||||
else:
|
||||
shared.log.warning('Compress VAE Text Encoder Weights enabled but model has no Text Encoder')
|
||||
t1 = time.time()
|
||||
|
||||
+34
-43
@@ -6,16 +6,10 @@ import platform
|
||||
import subprocess
|
||||
from functools import reduce
|
||||
import gradio as gr
|
||||
from modules import call_queue, shared, prompt_parser
|
||||
from modules import generation_parameters_copypaste
|
||||
from modules import ui_sections
|
||||
from modules.ui_components import ToolButton
|
||||
import modules.ui_symbols as symbols
|
||||
import modules.images
|
||||
import modules.script_callbacks
|
||||
from modules import call_queue, shared, prompt_parser, ui_sections, ui_symbols, ui_components, generation_parameters_copypaste, images, scripts, script_callbacks
|
||||
|
||||
|
||||
folder_symbol = symbols.folder
|
||||
folder_symbol = ui_symbols.folder
|
||||
debug = shared.log.trace if os.environ.get('SD_PASTE_DEBUG', None) is not None else lambda *args, **kwargs: None
|
||||
debug('Trace: PASTE')
|
||||
|
||||
@@ -58,19 +52,19 @@ def infotext_to_html(text):
|
||||
return code
|
||||
|
||||
|
||||
def delete_files(js_data, images, _html_info, index):
|
||||
def delete_files(js_data, files, _html_info, index):
|
||||
try:
|
||||
data = json.loads(js_data)
|
||||
except Exception:
|
||||
data = { 'index_of_first_image': 0 }
|
||||
start_index = 0
|
||||
if index > -1 and shared.opts.save_selected_only and (index >= data['index_of_first_image']):
|
||||
images = [images[index]]
|
||||
files = [files[index]]
|
||||
start_index = index
|
||||
filenames = []
|
||||
filenames = []
|
||||
fullfns = []
|
||||
for _image_index, filedata in enumerate(images, start_index):
|
||||
for _image_index, filedata in enumerate(files, start_index):
|
||||
if 'name' in filedata and os.path.isfile(filedata['name']):
|
||||
fullfn = filedata['name']
|
||||
filenames.append(os.path.basename(fullfn))
|
||||
@@ -84,11 +78,11 @@ def delete_files(js_data, images, _html_info, index):
|
||||
shared.log.info(f"Deleting image: {fullfn}")
|
||||
except Exception as e:
|
||||
shared.log.error(f'Error deleting file: {fullfn} {e}')
|
||||
images = [image for image in images if image['name'] not in fullfns]
|
||||
return images, plaintext_to_html(f"Deleted: {filenames[0] if len(filenames) > 0 else 'none'}")
|
||||
files = [image for image in files if image['name'] not in fullfns]
|
||||
return files, plaintext_to_html(f"Deleted: {filenames[0] if len(filenames) > 0 else 'none'}")
|
||||
|
||||
|
||||
def save_files(js_data, images, html_info, index):
|
||||
def save_files(js_data, files, html_info, index):
|
||||
os.makedirs(shared.opts.outdir_save, exist_ok=True)
|
||||
|
||||
class PObject: # pylint: disable=too-few-public-methods
|
||||
@@ -117,11 +111,11 @@ def save_files(js_data, images, html_info, index):
|
||||
p = PObject(data)
|
||||
start_index = 0
|
||||
if index > -1 and shared.opts.save_selected_only and (index >= p.index_of_first_image): # ensures we are looking at a specific non-grid picture, and we have save_selected_only # pylint: disable=no-member
|
||||
images = [images[index]]
|
||||
files = [files[index]]
|
||||
start_index = index
|
||||
filenames = []
|
||||
fullfns = []
|
||||
for image_index, filedata in enumerate(images, start_index):
|
||||
for image_index, filedata in enumerate(files, start_index):
|
||||
is_grid = image_index < p.index_of_first_image # pylint: disable=no-member
|
||||
i = 0 if is_grid else (image_index - p.index_of_first_image) # pylint: disable=no-member
|
||||
while len(p.all_seeds) <= i:
|
||||
@@ -135,7 +129,7 @@ def save_files(js_data, images, html_info, index):
|
||||
filenames.append(os.path.basename(fullfn))
|
||||
fullfns.append(fullfn)
|
||||
destination = shared.opts.outdir_save
|
||||
namegen = modules.images.FilenameGenerator(p, seed=p.all_seeds[i], prompt=p.all_prompts[i], image=None) # pylint: disable=no-member
|
||||
namegen = images.FilenameGenerator(p, seed=p.all_seeds[i], prompt=p.all_prompts[i], image=None) # pylint: disable=no-member
|
||||
dirname = namegen.apply(shared.opts.directories_filename_pattern or "[prompt_words]").lstrip(' ').rstrip('\\ /')
|
||||
destination = os.path.join(destination, dirname)
|
||||
destination = namegen.sanitize(destination)
|
||||
@@ -154,11 +148,11 @@ def save_files(js_data, images, html_info, index):
|
||||
shared.log.debug(f'Saving: text="{filename_txt}"')
|
||||
except Exception as e:
|
||||
shared.log.warning(f'Image description save failed: {filename_txt} {e}')
|
||||
modules.script_callbacks.image_save_btn_callback(tgt_filename)
|
||||
script_callbacks.image_save_btn_callback(tgt_filename)
|
||||
else:
|
||||
image = generation_parameters_copypaste.image_from_url_text(filedata)
|
||||
info = p.infotexts[i + 1] if len(p.infotexts) > len(p.all_seeds) else p.infotexts[i] # infotexts may be offset by 1 because the first image is the grid
|
||||
fullfn, txt_fullfn = modules.images.save_image(image, shared.opts.outdir_save, "", seed=p.all_seeds[i], prompt=p.all_prompts[i], info=info, extension=shared.opts.samples_format, grid=is_grid, p=p)
|
||||
fullfn, txt_fullfn = images.save_image(image, shared.opts.outdir_save, "", seed=p.all_seeds[i], prompt=p.all_prompts[i], info=info, extension=shared.opts.samples_format, grid=is_grid, p=p)
|
||||
if fullfn is None:
|
||||
continue
|
||||
filename = os.path.relpath(fullfn, shared.opts.outdir_save)
|
||||
@@ -167,7 +161,7 @@ def save_files(js_data, images, html_info, index):
|
||||
if txt_fullfn:
|
||||
filenames.append(os.path.basename(txt_fullfn))
|
||||
# fullfns.append(txt_fullfn)
|
||||
modules.script_callbacks.image_save_btn_callback(filename)
|
||||
script_callbacks.image_save_btn_callback(filename)
|
||||
if shared.opts.samples_save_zip and len(fullfns) > 1:
|
||||
zip_filepath = os.path.join(shared.opts.outdir_save, "images.zip")
|
||||
from zipfile import ZipFile
|
||||
@@ -277,11 +271,11 @@ def create_output_panel(tabname, preview=True, prompt=None, height=None):
|
||||
)
|
||||
|
||||
if tabname == "txt2img":
|
||||
paste_field_names = modules.scripts.scripts_txt2img.paste_field_names
|
||||
paste_field_names = scripts.scripts_txt2img.paste_field_names
|
||||
elif tabname == "img2img":
|
||||
paste_field_names = modules.scripts.scripts_img2img.paste_field_names
|
||||
paste_field_names = scripts.scripts_img2img.paste_field_names
|
||||
elif tabname == "control":
|
||||
paste_field_names = modules.scripts.scripts_control.paste_field_names
|
||||
paste_field_names = scripts.scripts_control.paste_field_names
|
||||
else:
|
||||
paste_field_names = []
|
||||
for paste_tabname, paste_button in buttons.items():
|
||||
@@ -299,7 +293,7 @@ def create_refresh_button(refresh_component, refresh_method, refreshed_args, ele
|
||||
setattr(refresh_component, k, v)
|
||||
return gr.update(**(args or {}))
|
||||
|
||||
refresh_button = ToolButton(value=symbols.refresh, elem_id=elem_id, visible=visible)
|
||||
refresh_button = ui_components.ToolButton(value=ui_symbols.refresh, elem_id=elem_id, visible=visible)
|
||||
refresh_button.click(fn=refresh, inputs=[], outputs=[refresh_component])
|
||||
return refresh_button
|
||||
|
||||
@@ -311,7 +305,7 @@ def create_browse_button(browse_component, elem_id):
|
||||
return gr.update(value = folder)
|
||||
return gr.update()
|
||||
|
||||
browse_button = ToolButton(value=symbols.folder, elem_id=elem_id)
|
||||
browse_button = ui_components.ToolButton(value=ui_symbols.folder, elem_id=elem_id)
|
||||
browse_button.click(fn=browse, _js="async () => await browseFolder()", inputs=[browse_component], outputs=[browse_component])
|
||||
# browse_button.click(fn=browse, inputs=[browse_component], outputs=[browse_component])
|
||||
return browse_button
|
||||
@@ -352,33 +346,30 @@ def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info:
|
||||
|
||||
|
||||
def update_token_counter(text, steps):
|
||||
from modules import extra_networks, sd_hijack
|
||||
token_count = 0
|
||||
max_length = 75
|
||||
if shared.state.job_count > 0:
|
||||
shared.log.info('Tokenizer busy')
|
||||
return f"<span class='gr-box gr-text-input'>{token_count}/{max_length}</span>"
|
||||
from modules import extra_networks
|
||||
try:
|
||||
text, _ = extra_networks.parse_prompt(text)
|
||||
_, prompt_flat_list, _ = prompt_parser.get_multicond_prompt_list([text])
|
||||
prompt_schedules = prompt_parser.get_learned_conditioning_prompt_schedules(prompt_flat_list, steps)
|
||||
except Exception:
|
||||
prompt_schedules = [[[steps, text]]]
|
||||
|
||||
flat_prompts = reduce(lambda list1, list2: list1+list2, prompt_schedules)
|
||||
prompts = [prompt_text for step, prompt_text in flat_prompts]
|
||||
if shared.backend == shared.Backend.ORIGINAL:
|
||||
from modules import sd_hijack
|
||||
token_count, max_length = max([sd_hijack.model_hijack.get_prompt_lengths(prompt) for prompt in prompts], key=lambda args: args[0])
|
||||
elif shared.backend == shared.Backend.DIFFUSERS:
|
||||
if shared.sd_model is not None and hasattr(shared.sd_model, 'tokenizer'):
|
||||
tokenizer = shared.sd_model.tokenizer
|
||||
if tokenizer is None:
|
||||
token_count = 0
|
||||
max_length = 75
|
||||
else:
|
||||
has_bos_token = tokenizer.bos_token_id is not None
|
||||
has_eos_token = tokenizer.eos_token_id is not None
|
||||
ids = [shared.sd_model.tokenizer(prompt) for prompt in prompts]
|
||||
if len(ids) > 0 and hasattr(ids[0], 'input_ids'):
|
||||
ids = [x.input_ids for x in ids]
|
||||
token_count = max([len(x) for x in ids]) - int(has_bos_token) - int(has_eos_token)
|
||||
max_length = tokenizer.model_max_length - int(has_bos_token) - int(has_eos_token)
|
||||
else:
|
||||
token_count = 0
|
||||
max_length = 75
|
||||
if shared.sd_model is not None and hasattr(shared.sd_model, 'tokenizer') and shared.sd_model.tokenizer is not None:
|
||||
has_bos_token = shared.sd_model.tokenizer.bos_token_id is not None
|
||||
has_eos_token = shared.sd_model.tokenizer.eos_token_id is not None
|
||||
ids = [shared.sd_model.tokenizer(prompt) for prompt in prompts]
|
||||
if len(ids) > 0 and hasattr(ids[0], 'input_ids'):
|
||||
ids = [x.input_ids for x in ids]
|
||||
token_count = max([len(x) for x in ids]) - int(has_bos_token) - int(has_eos_token)
|
||||
max_length = shared.sd_model.tokenizer.model_max_length - int(has_bos_token) - int(has_eos_token)
|
||||
return f"<span class='gr-box gr-text-input'>{token_count}/{max_length}</span>"
|
||||
|
||||
@@ -13,7 +13,7 @@ import torch # pylint: disable=wrong-import-order
|
||||
from modules import timer, errors, paths # pylint: disable=unused-import
|
||||
from installer import log, git_commit, custom_excepthook
|
||||
import ldm.modules.encoders.modules # pylint: disable=W0611,C0411,E0401
|
||||
from modules import shared, extensions, ui_tempdir, modelloader # pylint: disable=ungrouped-imports
|
||||
from modules import shared, extensions, gr_tempdir, modelloader # pylint: disable=ungrouped-imports
|
||||
from modules import extra_networks, ui_extra_networks # pylint: disable=ungrouped-imports
|
||||
from modules.paths import create_paths
|
||||
from modules.call_queue import queue_lock, wrap_queued_call, wrap_gradio_gpu_call # pylint: disable=W0611,C0411,C0412
|
||||
@@ -111,7 +111,7 @@ def initialize():
|
||||
timer.startup.record("upscalers")
|
||||
|
||||
shared.opts.onchange("sd_vae", wrap_queued_call(lambda: modules.sd_vae.reload_vae_weights()), call=False)
|
||||
shared.opts.onchange("temp_dir", ui_tempdir.on_tmpdir_changed)
|
||||
shared.opts.onchange("temp_dir", gr_tempdir.on_tmpdir_changed)
|
||||
timer.startup.record("onchange")
|
||||
|
||||
modules.textual_inversion.textual_inversion.list_textual_inversion_templates()
|
||||
@@ -212,7 +212,7 @@ def start_common():
|
||||
async_policy()
|
||||
initialize()
|
||||
if shared.opts.clean_temp_dir_at_start:
|
||||
ui_tempdir.cleanup_tmpdr()
|
||||
gr_tempdir.cleanup_tmpdr()
|
||||
timer.startup.record("cleanup")
|
||||
|
||||
|
||||
@@ -269,7 +269,7 @@ def start_ui():
|
||||
_frontend=True and cmd_opts.share,
|
||||
)
|
||||
if cmd_opts.data_dir is not None:
|
||||
ui_tempdir.register_tmp_file(shared.demo, os.path.join(cmd_opts.data_dir, 'x'))
|
||||
gr_tempdir.register_tmp_file(shared.demo, os.path.join(cmd_opts.data_dir, 'x'))
|
||||
shared.log.info(f'Local URL: {local_url}')
|
||||
if cmd_opts.docs:
|
||||
shared.log.info(f'API Docs: {local_url[:-1]}/docs') # pylint: disable=unsubscriptable-object
|
||||
|
||||
+1
-1
Submodule wiki updated: 102ab490f3...6fc48f5d84
Reference in New Issue
Block a user