mirror of
https://github.com/vladmandic/automatic
synced 2026-09-20 01:31:13 +02:00
update api and img2img
This commit is contained in:
@@ -40,6 +40,8 @@
|
||||
- fix extra networks sort
|
||||
- add hdr settings to metadata
|
||||
- improve handling of long filenames and filenames during batch processing
|
||||
- do not set preview samples when using via api
|
||||
- avoid unnecessary resizes in img2img and inpaint
|
||||
- update built-in log monitor in ui, thanks @midcoastal
|
||||
|
||||
## Update for 2023-12-04
|
||||
|
||||
@@ -58,6 +58,13 @@ def generate(args): # pylint: disable=redefined-outer-name
|
||||
options['steps'] = int(args.steps)
|
||||
options['seed'] = int(args.seed)
|
||||
options['sampler_name'] = args.sampler
|
||||
options['init_images'] = [encode(args.init)]
|
||||
image = Image.open(args.init)
|
||||
options['width'] = image.width
|
||||
options['height'] = image.height
|
||||
image.close()
|
||||
if args.mask is not None:
|
||||
options['mask'] = encode(args.mask)
|
||||
data = post('/sdapi/v1/img2img', options)
|
||||
t1 = time.time()
|
||||
if 'images' in data:
|
||||
|
||||
+4
-4
@@ -287,14 +287,14 @@ class Api:
|
||||
p.scripts = script_runner
|
||||
p.outpath_grids = shared.opts.outdir_grids or shared.opts.outdir_txt2img_grids
|
||||
p.outpath_samples = shared.opts.outdir_samples or shared.opts.outdir_txt2img_samples
|
||||
shared.state.begin('api-txt2img')
|
||||
shared.state.begin('api-txt2img', api=True)
|
||||
script_args = self.init_script_args(p, txt2imgreq, self.default_script_arg_txt2img, selectable_scripts, selectable_script_idx, script_runner)
|
||||
if selectable_scripts is not None:
|
||||
processed = scripts.scripts_txt2img.run(p, *script_args) # Need to pass args as list here
|
||||
else:
|
||||
p.script_args = tuple(script_args) # Need to pass args as tuple here
|
||||
processed = process_images(p)
|
||||
shared.state.end()
|
||||
shared.state.end(api=False)
|
||||
|
||||
b64images = list(map(encode_pil_to_base64, processed.images)) if send_images else []
|
||||
return models.TextToImageResponse(images=b64images, parameters=vars(txt2imgreq), info=processed.js())
|
||||
@@ -335,14 +335,14 @@ class Api:
|
||||
p.scripts = script_runner
|
||||
p.outpath_grids = shared.opts.outdir_img2img_grids
|
||||
p.outpath_samples = shared.opts.outdir_img2img_samples
|
||||
shared.state.begin('api-img2img')
|
||||
shared.state.begin('api-img2img', api=True)
|
||||
script_args = self.init_script_args(p, img2imgreq, self.default_script_arg_img2img, selectable_scripts, selectable_script_idx, script_runner)
|
||||
if selectable_scripts is not None:
|
||||
processed = scripts.scripts_img2img.run(p, *script_args) # Need to pass args as list here
|
||||
else:
|
||||
p.script_args = tuple(script_args) # Need to pass args as tuple here
|
||||
processed = process_images(p)
|
||||
shared.state.end()
|
||||
shared.state.end(api=False)
|
||||
|
||||
b64images = list(map(encode_pil_to_base64, processed.images)) if send_images else []
|
||||
if not img2imgreq.include_init_images:
|
||||
|
||||
+2
-4
@@ -211,7 +211,7 @@ def draw_prompt_matrix(im, width, height, all_prompts, margin=0):
|
||||
|
||||
|
||||
def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type='image'):
|
||||
# shared.log.debug(f'Image resize: mode={resize_mode} resolution={width}x{height} upscaler={upscaler_name}')
|
||||
shared.log.debug(f'Image resize: mode={resize_mode} resolution={width}x{height} upscaler={upscaler_name} function={sys._getframe(1).f_code.co_name}') # pylint: disable=protected-access
|
||||
"""
|
||||
Resizes an image with the specified resize_mode, width, and height.
|
||||
Args:
|
||||
@@ -243,9 +243,7 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type
|
||||
im = im.resize((w, h), resample=Image.Resampling.LANCZOS)
|
||||
return im
|
||||
|
||||
if resize_mode == 0:
|
||||
res = im.copy()
|
||||
if width == 0 or height == 0:
|
||||
if resize_mode == 0 or (im.width == width and im.height == height):
|
||||
res = im.copy()
|
||||
elif resize_mode == 1:
|
||||
res = resize(im, width, height)
|
||||
|
||||
+4
-1
@@ -9,6 +9,9 @@ from modules.ui import plaintext_to_html
|
||||
from modules.memstats import memory_stats
|
||||
|
||||
|
||||
debug = shared.log.debug if os.environ.get('SD_PROCESS_DEBUG', None) is not None else lambda *args, **kwargs: None
|
||||
|
||||
|
||||
def process_batch(p, input_files, input_dir, output_dir, inpaint_mask_dir, args):
|
||||
shared.log.debug(f'batch: {input_files}|{input_dir}|{output_dir}|{inpaint_mask_dir}')
|
||||
processing.fix_seed(p)
|
||||
@@ -106,7 +109,7 @@ def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_s
|
||||
shared.log.warning('Model not loaded')
|
||||
return [], '', '', 'Error: model not loaded'
|
||||
|
||||
shared.log.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}|latent_index={latent_index}|mask_blur={mask_blur}|mask_alpha={mask_alpha}|inpainting_fill={inpainting_fill}|full_quality={full_quality}|restore_faces={restore_faces}|tiling={tiling}|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}|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}')
|
||||
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}|latent_index={latent_index}|mask_blur={mask_blur}|mask_alpha={mask_alpha}|inpainting_fill={inpainting_fill}|full_quality={full_quality}|restore_faces={restore_faces}|tiling={tiling}|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}|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 mode == 5:
|
||||
if img2img_batch_files is None or len(img2img_batch_files) == 0:
|
||||
|
||||
+16
-8
@@ -44,6 +44,8 @@ from modules.sd_hijack_hypertile import context_hypertile_vae, context_hypertile
|
||||
|
||||
opt_C = 4
|
||||
opt_f = 8
|
||||
debug = shared.log.debug if os.environ.get('SD_PROCESS_DEBUG', None) is not None else lambda *args, **kwargs: None
|
||||
|
||||
|
||||
def setup_color_correction(image):
|
||||
shared.log.debug("Calibrating color correction.")
|
||||
@@ -64,10 +66,11 @@ def apply_overlay(image: Image, paste_loc, index, overlays):
|
||||
overlay = overlays[index]
|
||||
if paste_loc is not None:
|
||||
x, y, w, h = paste_loc
|
||||
base_image = Image.new('RGBA', (overlay.width, overlay.height))
|
||||
image = images.resize_image(2, image, w, h)
|
||||
base_image.paste(image, (x, y))
|
||||
image = base_image
|
||||
if image.width != w or image.height != h or x != 0 or y != 0:
|
||||
base_image = Image.new('RGBA', (overlay.width, overlay.height))
|
||||
image = images.resize_image(2, image, w, h)
|
||||
base_image.paste(image, (x, y))
|
||||
image = base_image
|
||||
image = image.convert('RGBA')
|
||||
image.alpha_composite(overlay)
|
||||
image = image.convert('RGB')
|
||||
@@ -667,6 +670,7 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No
|
||||
|
||||
|
||||
def process_images(p: StableDiffusionProcessing) -> Processed:
|
||||
debug(f'Process images: {vars(p)}')
|
||||
if not hasattr(p.sd_model, 'sd_checkpoint_info'):
|
||||
return None
|
||||
if p.scripts is not None and isinstance(p.scripts, modules.scripts.ScriptRunner):
|
||||
@@ -1241,10 +1245,12 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
||||
crop_region = modules.masking.expand_crop_region(crop_region, self.width, self.height, mask.width, mask.height)
|
||||
x1, y1, x2, y2 = crop_region
|
||||
mask = mask.crop(crop_region)
|
||||
image_mask = images.resize_image(3, mask, self.width, self.height)
|
||||
if mask.width != self.width or mask.height != self.height:
|
||||
image_mask = images.resize_image(3, mask, self.width, self.height)
|
||||
self.paste_to = (x1, y1, x2-x1, y2-y1)
|
||||
else:
|
||||
image_mask = images.resize_image(self.resize_mode, image_mask, self.width, self.height)
|
||||
if image_mask.width != self.width or image_mask.height != self.height:
|
||||
image_mask = images.resize_image(self.resize_mode, image_mask, self.width, self.height)
|
||||
np_mask = np.array(image_mask)
|
||||
np_mask = np.clip((np_mask.astype(np.float32)) * 2, 0, 255).astype(np.uint8)
|
||||
self.mask_for_overlay = Image.fromarray(np_mask)
|
||||
@@ -1264,7 +1270,8 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
||||
images.save_image(img, path=shared.opts.outdir_init_images, basename=None, forced_filename=self.init_img_hash, suffix="-init-image")
|
||||
image = images.flatten(img, shared.opts.img2img_background_color)
|
||||
if crop_region is None and self.resize_mode != 4:
|
||||
image = images.resize_image(self.resize_mode, image, self.width, self.height)
|
||||
if image.width != self.width or image.height != self.height:
|
||||
image = images.resize_image(self.resize_mode, image, self.width, self.height)
|
||||
self.width = image.width
|
||||
self.height = image.height
|
||||
if image_mask is not None:
|
||||
@@ -1280,7 +1287,8 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
||||
# crop_region is not None if we are doing inpaint full res
|
||||
if crop_region is not None:
|
||||
image = image.crop(crop_region)
|
||||
image = images.resize_image(3, image, self.width, self.height)
|
||||
if image.width != self.width or image.height != self.height:
|
||||
image = images.resize_image(3, image, self.width, self.height)
|
||||
if image_mask is not None and self.inpainting_fill != 1:
|
||||
image = modules.masking.fill(image, latent_mask)
|
||||
if add_color_corrections:
|
||||
|
||||
@@ -21,6 +21,7 @@ class State:
|
||||
current_image_sampling_step = 0
|
||||
id_live_preview = 0
|
||||
textinfo = None
|
||||
api = False
|
||||
time_start = None
|
||||
need_restart = False
|
||||
server_start = time.time()
|
||||
@@ -58,7 +59,7 @@ class State:
|
||||
}
|
||||
return obj
|
||||
|
||||
def begin(self, title=""):
|
||||
def begin(self, title="", api=None):
|
||||
import modules.devices
|
||||
self.total_jobs += 1
|
||||
self.current_image = None
|
||||
@@ -74,12 +75,13 @@ class State:
|
||||
self.sampling_step = 0
|
||||
self.skipped = False
|
||||
self.textinfo = None
|
||||
self.api = api if api is not None else self.api
|
||||
self.time_start = time.time()
|
||||
if self.debug_output:
|
||||
log.debug(f'State begin: {self.job}')
|
||||
modules.devices.torch_gc()
|
||||
|
||||
def end(self):
|
||||
def end(self, api=None):
|
||||
import modules.devices
|
||||
if self.time_start is None: # someone called end before being
|
||||
log.debug(f'Access state.end: {sys._getframe().f_back.f_code.co_name}') # pylint: disable=protected-access
|
||||
@@ -92,20 +94,21 @@ class State:
|
||||
self.paused = False
|
||||
self.interrupted = False
|
||||
self.skipped = False
|
||||
self.api = api if api is not None else self.api
|
||||
modules.devices.torch_gc()
|
||||
|
||||
def set_current_image(self):
|
||||
from modules.shared import opts, cmd_opts
|
||||
"""sets self.current_image from self.current_latent if enough sampling steps have been made after the last call to this"""
|
||||
if cmd_opts.lowvram:
|
||||
if cmd_opts.lowvram or self.api:
|
||||
return
|
||||
if abs(self.sampling_step - self.current_image_sampling_step) >= opts.show_progress_every_n_steps and opts.live_previews_enable and opts.show_progress_every_n_steps > 0:
|
||||
self.do_set_current_image()
|
||||
|
||||
def do_set_current_image(self):
|
||||
from modules.shared import opts
|
||||
if self.current_latent is None:
|
||||
if self.current_latent is None or self.api:
|
||||
return
|
||||
from modules.shared import opts
|
||||
import modules.sd_samplers # pylint: disable=W0621
|
||||
try:
|
||||
image = modules.sd_samplers.samples_to_image_grid(self.current_latent) if opts.show_progress_grid else modules.sd_samplers.sample_to_image(self.current_latent)
|
||||
|
||||
+5
-1
@@ -1,12 +1,16 @@
|
||||
import os
|
||||
import modules.scripts
|
||||
from modules import sd_samplers, shared, processing
|
||||
from modules.generation_parameters_copypaste import create_override_settings_dict
|
||||
from modules.ui import plaintext_to_html
|
||||
|
||||
|
||||
debug = shared.log.debug if os.environ.get('SD_PROCESS_DEBUG', None) is not None else lambda *args, **kwargs: None
|
||||
|
||||
|
||||
def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, steps: int, sampler_index: int, latent_index: int, full_quality: bool, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, image_cfg_scale: float, diffusers_guidance_rescale: float, clip_skip: int, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, height: int, width: int, enable_hr: bool, denoising_strength: float, hr_scale: float, hr_upscaler: str, hr_force: bool, hr_second_pass_steps: int, hr_resize_x: int, hr_resize_y: int, refiner_steps: int, refiner_start: int, refiner_prompt: str, refiner_negative: str, hdr_clamp, hdr_boundary, hdr_threshold, hdr_center, hdr_channel_shift, hdr_full_shift, hdr_maximize, hdr_max_center, hdr_max_boundry, override_settings_texts, *args): # pylint: disable=unused-argument
|
||||
|
||||
shared.log.debug(f'txt2img: id_task={id_task}|prompt={prompt}|negative_prompt={negative_prompt}|prompt_styles={prompt_styles}|steps={steps}|sampler_index={sampler_index}|latent_index={latent_index}|full_quality={full_quality}|restore_faces={restore_faces}|tiling={tiling}|n_iter={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_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_texts={override_settings_texts}')
|
||||
debug(f'txt2img: id_task={id_task}|prompt={prompt}|negative_prompt={negative_prompt}|prompt_styles={prompt_styles}|steps={steps}|sampler_index={sampler_index}|latent_index={latent_index}|full_quality={full_quality}|restore_faces={restore_faces}|tiling={tiling}|n_iter={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_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_texts={override_settings_texts}')
|
||||
|
||||
if shared.sd_model is None:
|
||||
shared.log.warning('Model not loaded')
|
||||
|
||||
Reference in New Issue
Block a user