mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 17:24:32 +02:00
Merge pull request #4886 from vladmandic/feat/detailer-postprocess
feat(api): add detailer postprocess script and /sdapi/v1/detail endpoint
This commit is contained in:
@@ -69,6 +69,7 @@ class Api:
|
||||
self.add_api_route("/sdapi/v1/preprocess", self.process.post_preprocess, methods=["POST"], tags=["Processing"])
|
||||
self.add_api_route("/sdapi/v1/mask", self.process.post_mask, methods=["POST"], tags=["Processing"])
|
||||
self.add_api_route("/sdapi/v1/detect", self.process.post_detect, methods=["POST"], tags=["Processing"])
|
||||
self.add_api_route("/sdapi/v1/detail", self.process.post_detail, methods=["POST"], response_model=models.ResDetail, tags=["Processing"])
|
||||
self.add_api_route("/sdapi/v1/prompt-enhance", self.process.post_prompt_enhance, methods=["POST"], response_model=models.ResPromptEnhance, tags=["Generation"])
|
||||
|
||||
# api dealing with optional scripts
|
||||
|
||||
@@ -343,6 +343,7 @@ class ReqProcess(BaseModel):
|
||||
upscaler_1: str = Field(default="None", title="Main upscaler", description=f"The name of the main upscaler to use, it has to be one of this list: {' , '.join([x.name for x in shared.sd_upscalers])}")
|
||||
upscaler_2: str = Field(default="None", title="Refine upscaler", description=f"The name of the secondary upscaler to use, it has to be one of this list: {' , '.join([x.name for x in shared.sd_upscalers])}")
|
||||
extras_upscaler_2_visibility: float = Field(default=0, title="Refine upscaler visibility", ge=0, le=1, allow_inf_nan=False, description="Sets the visibility of secondary upscaler, values should be between 0 and 1.")
|
||||
script_args: dict | None = Field(default=None, title="Script args", description="Per-script arguments keyed by script name, e.g. {\"Detailer\": {\"strength\": 0.5}, \"Remove background\": {\"model\": \"u2net\"}}.")
|
||||
|
||||
class ResProcess(BaseModel):
|
||||
html_info: str = Field(title="HTML info", description="A series of HTML tags containing the process info.")
|
||||
@@ -391,6 +392,44 @@ class ReqProcessBatch(ReqProcess):
|
||||
class ResProcessBatch(ResProcess):
|
||||
images: list[str] = Field(title="Images", description="The generated images in base64 format.")
|
||||
|
||||
class ReqDetail(BaseModel):
|
||||
image: str = Field(title="Image", description="Base64-encoded input image to detail")
|
||||
seed: int | None = Field(default=-1, title="Seed", description="Seed for inpainting passes (-1 = random)")
|
||||
detailer_models: list[str] | None = Field(default=None, title="Detailer models", description="List of YOLO detailer model names to run; falls back to shared.opts.detailer_models when omitted")
|
||||
detailer_prompt: str | None = Field(default=None, title="Detailer prompt", description="Override prompt for detailer pass; supports [PROMPT]/[prompt] splice tokens")
|
||||
detailer_negative: str | None = Field(default=None, title="Detailer negative", description="Override negative prompt for detailer pass")
|
||||
detailer_steps: int | None = Field(default=None, ge=0, le=99, title="Detailer steps")
|
||||
detailer_strength: float | None = Field(default=None, ge=0.0, le=1.0, title="Detailer strength")
|
||||
detailer_resolution: int | None = Field(default=None, ge=256, le=4096, title="Detailer resolution")
|
||||
detailer_sampler: str | None = Field(default=None, title="Detailer sampler", description="Sampler name for the inpaint pass; a named sampler activates the scheduler overrides below, 'Default' keeps the model scheduler")
|
||||
detailer_prediction: str | None = Field(default=None, title="Detailer prediction", description="Scheduler prediction type override (default/epsilon/sample/v_prediction/flow_prediction)")
|
||||
detailer_shift: float | None = Field(default=None, ge=0.0, le=10.0, title="Detailer flow shift", description="Flow/sampler shift for the inpaint pass; needs a named sampler")
|
||||
detailer_cfg_scale: float | None = Field(default=None, ge=0.0, le=30.0, title="Detailer guidance scale", description="CFG/guidance scale for the inpaint pass")
|
||||
detailer_loworder: bool | None = Field(default=None, title="Detailer low order")
|
||||
detailer_thresholding: bool | None = Field(default=None, title="Detailer thresholding")
|
||||
detailer_dynamic: bool | None = Field(default=None, title="Detailer dynamic shift")
|
||||
detailer_rescale: bool | None = Field(default=None, title="Detailer rescale betas")
|
||||
detailer_classes: str | None = Field(default=None, title="Detailer classes", description="Comma-separated class allowlist (e.g. 'face,eye')")
|
||||
detailer_conf: float | None = Field(default=None, ge=0.0, le=1.0, title="Min confidence")
|
||||
detailer_iou: float | None = Field(default=None, ge=0.0, le=1.0, title="Max overlap (IoU)")
|
||||
detailer_max: int | None = Field(default=None, ge=1, title="Max detections")
|
||||
detailer_min_size: float | None = Field(default=None, ge=0.0, le=1.0, title="Min relative size")
|
||||
detailer_max_size: float | None = Field(default=None, ge=0.0, le=1.0, title="Max relative size")
|
||||
detailer_blur: int | None = Field(default=None, ge=0, le=100, title="Mask blur")
|
||||
detailer_padding: int | None = Field(default=None, ge=0, le=100, title="Mask padding")
|
||||
detailer_segmentation: bool | None = Field(default=None, title="Use segmentation", description="Use seg-mask instead of bbox (requires a -seg model)")
|
||||
detailer_merge: bool | None = Field(default=None, title="Merge detections")
|
||||
detailer_sort: bool | None = Field(default=None, title="Sort detections", description="Sort detections left-to-right for consistency")
|
||||
detailer_sigma_adjust: float | None = Field(default=None, ge=0.5, le=1.5, title="Renoise sigma")
|
||||
detailer_sigma_adjust_max: float | None = Field(default=None, ge=0.0, le=1.0, title="Renoise end")
|
||||
detailer_include_detections: bool | None = Field(default=None, title="Include detections", description="Return annotated debug image alongside the detailed result")
|
||||
|
||||
class ResDetail(BaseModel):
|
||||
image: str = Field(title="Image", description="Detailed image (base64)")
|
||||
detections: str | None = Field(default=None, title="Detections", description="Annotated debug image (base64) when detailer_include_detections=True")
|
||||
seed: int = Field(default=-1, title="Seed", description="Effective seed used for the detailer pass")
|
||||
info: str = Field(default='', title="Info", description="Postprocessing info string")
|
||||
|
||||
class ReqImageInfo(BaseModel):
|
||||
image: str = Field(title="Image", description="The base64 encoded image")
|
||||
|
||||
|
||||
+80
-5
@@ -137,6 +137,80 @@ class APIProcess:
|
||||
shared.state.end(jobid, api=False)
|
||||
return ResFace(classes=classes, labels=labels, scores=scores, boxes=boxes, images=images)
|
||||
|
||||
def post_detail(self, req: models.ReqDetail):
|
||||
"""Run the YOLO detailer on a single image as a standalone operation; no base generation pass.
|
||||
|
||||
Per-request fields override shared.opts.detailer_* via detailer_opt(p, attr) precedence
|
||||
in modules/postprocess/yolo.py. Fields left as None fall through to the global setting.
|
||||
"""
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
from modules.shared import yolo # pylint: disable=no-name-in-module
|
||||
|
||||
if shared.sd_model is None or not hasattr(shared.sd_model, 'sd_checkpoint_info'):
|
||||
return JSONResponse(status_code=400, content={"error": "no base model selected"})
|
||||
image = decode_base64_to_image(req.image)
|
||||
if image is None:
|
||||
return JSONResponse(status_code=400, content={"error": "invalid image"})
|
||||
|
||||
# Per-request overrides for the non-primary detailer fields; None values fall through to opts
|
||||
# via detailer_opt(p, attr) -> shared.opts.<attr>.
|
||||
overrides = {attr: getattr(req, attr) for attr in (
|
||||
'detailer_models', 'detailer_classes', 'detailer_conf',
|
||||
'detailer_iou', 'detailer_max', 'detailer_min_size',
|
||||
'detailer_max_size', 'detailer_blur', 'detailer_padding',
|
||||
'detailer_segmentation', 'detailer_merge', 'detailer_sort',
|
||||
'detailer_sigma_adjust', 'detailer_sigma_adjust_max',
|
||||
'detailer_include_detections',
|
||||
) if getattr(req, attr, None) is not None}
|
||||
|
||||
# Sampler block: request field names differ from the p attributes they set, so map explicitly.
|
||||
# schedulers_* become per-job overrides (need a named sampler to take effect); cfg/sampler apply directly.
|
||||
for req_attr, p_attr in (
|
||||
('detailer_sampler', 'hr_sampler_name'),
|
||||
('detailer_prediction', 'schedulers_prediction_type'),
|
||||
('detailer_shift', 'schedulers_shift'),
|
||||
('detailer_cfg_scale', 'cfg_scale'),
|
||||
('detailer_loworder', 'schedulers_use_loworder'),
|
||||
('detailer_thresholding', 'schedulers_use_thresholding'),
|
||||
('detailer_dynamic', 'schedulers_dynamic_shift'),
|
||||
('detailer_rescale', 'schedulers_rescale_betas'),
|
||||
):
|
||||
val = getattr(req, req_attr, None)
|
||||
if val is not None:
|
||||
overrides[p_attr] = val
|
||||
|
||||
jobid = shared.state.begin('API-DETAIL', api=True)
|
||||
try:
|
||||
p = yolo.make_processing(
|
||||
image,
|
||||
prompt=req.detailer_prompt or '',
|
||||
negative=req.detailer_negative or '',
|
||||
steps=req.detailer_steps if req.detailer_steps is not None else 10,
|
||||
strength=req.detailer_strength if req.detailer_strength is not None else 0.3,
|
||||
resolution=req.detailer_resolution if req.detailer_resolution is not None else 1024,
|
||||
seed=req.seed if req.seed is not None else -1,
|
||||
overrides=overrides,
|
||||
)
|
||||
|
||||
with self.queue_lock:
|
||||
result = yolo.restore(np.array(image), p)
|
||||
|
||||
annotated_b64 = None
|
||||
if isinstance(result, list) and len(result) > 0:
|
||||
out_image = Image.fromarray(result[0])
|
||||
if len(result) > 1 and result[1] is not None:
|
||||
annotated = result[1] if isinstance(result[1], Image.Image) else Image.fromarray(result[1])
|
||||
annotated_b64 = encode_pil_to_base64(annotated)
|
||||
elif isinstance(result, np.ndarray):
|
||||
out_image = Image.fromarray(result)
|
||||
else:
|
||||
return JSONResponse(status_code=500, content={"error": "detailer produced no result"})
|
||||
|
||||
return models.ResDetail(image=encode_pil_to_base64(out_image), detections=annotated_b64, seed=p.all_seeds[0])
|
||||
finally:
|
||||
shared.state.end(jobid, api=False)
|
||||
|
||||
def post_prompt_enhance(self, req: models.ReqPromptEnhance):
|
||||
"""Enhance a prompt using an LLM. Supports text, image-conditioned, and video prompt enhancement modes."""
|
||||
from modules import processing_helpers
|
||||
@@ -209,23 +283,24 @@ class APIProcess:
|
||||
|
||||
def set_upscalers(self, req: dict):
|
||||
reqDict = vars(req)
|
||||
script_args = reqDict.pop('script_args', None)
|
||||
reqDict['extras_upscaler_1'] = reqDict.pop('upscaler_1', None)
|
||||
reqDict['extras_upscaler_2'] = reqDict.pop('upscaler_2', None)
|
||||
return reqDict
|
||||
return reqDict, script_args
|
||||
|
||||
def extras_single_image_api(self, req: models.ReqProcessImage):
|
||||
"""Upscale or postprocess a single image using the configured upscaler pipeline."""
|
||||
reqDict = self.set_upscalers(req)
|
||||
reqDict, script_args = self.set_upscalers(req)
|
||||
reqDict['image'] = helpers.decode_base64_to_image(reqDict['image'])
|
||||
with self.queue_lock:
|
||||
result = postprocessing.run_extras(extras_mode=0, image_folder="", input_dir="", output_dir="", save_output=False, **reqDict)
|
||||
result = postprocessing.run_extras(extras_mode=0, image_folder="", input_dir="", output_dir="", save_output=False, script_args=script_args, **reqDict)
|
||||
return models.ResProcessImage(image=helpers.encode_pil_to_base64(result[0][0]), html_info=result[1])
|
||||
|
||||
def extras_batch_images_api(self, req: models.ReqProcessBatch):
|
||||
"""Upscale or postprocess a batch of images using the configured upscaler pipeline."""
|
||||
reqDict = self.set_upscalers(req)
|
||||
reqDict, script_args = self.set_upscalers(req)
|
||||
image_list = reqDict.pop('imageList', [])
|
||||
image_folder = [helpers.decode_base64_to_image(x.data) for x in image_list]
|
||||
with self.queue_lock:
|
||||
result = postprocessing.run_extras(extras_mode=1, image_folder=image_folder, image="", input_dir="", output_dir="", save_output=False, **reqDict)
|
||||
result = postprocessing.run_extras(extras_mode=1, image_folder=image_folder, image="", input_dir="", output_dir="", save_output=False, script_args=script_args, **reqDict)
|
||||
return models.ResProcessBatch(images=list(map(helpers.encode_pil_to_base64, result[0])), html_info=result[1])
|
||||
|
||||
@@ -483,6 +483,51 @@ class YoloRestorer(Detailer):
|
||||
np_images.append(annotated) # save debug image with boxes
|
||||
return np_images
|
||||
|
||||
def make_processing(self, image, prompt='', negative='', steps=10, strength=0.3, resolution=1024, seed=-1, overrides=None):
|
||||
"""Build a synthetic Img2Img processing object to run restore() standalone, with no base generation pass.
|
||||
|
||||
The primary params map to the detailer_* fields restore() reads directly. overrides is an optional
|
||||
dict of the remaining detailer_* settings; None values are skipped and fall through to shared.opts
|
||||
via detailer_opt(). The seed is resolved here so restore()'s inpaint passes are reproducible and the
|
||||
effective value can be reported back.
|
||||
"""
|
||||
from modules.processing_helpers import get_fixed_seed
|
||||
from modules.paths import resolve_output_path
|
||||
seed = int(get_fixed_seed(seed))
|
||||
outpath = resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_extras_samples)
|
||||
p = processing.StableDiffusionProcessingImg2Img(
|
||||
sd_model=shared.sd_model,
|
||||
prompt=prompt or '',
|
||||
negative_prompt=negative or '',
|
||||
init_images=[image],
|
||||
outpath_samples=outpath,
|
||||
outpath_grids=outpath,
|
||||
batch_size=1,
|
||||
n_iter=1,
|
||||
seed=seed,
|
||||
width=image.width,
|
||||
height=image.height,
|
||||
detailer_enabled=True,
|
||||
detailer_prompt=prompt or '',
|
||||
detailer_negative=negative or '',
|
||||
detailer_steps=steps,
|
||||
detailer_strength=strength,
|
||||
detailer_resolution=resolution,
|
||||
)
|
||||
for attr, val in (overrides or {}).items():
|
||||
if val is not None:
|
||||
setattr(p, attr, val)
|
||||
# restore() at yolo.py reads all_prompts[0]/all_negative_prompts[0]; the rest avoid AttributeError downstream
|
||||
p.all_prompts = [p.detailer_prompt or '']
|
||||
p.all_negative_prompts = [p.detailer_negative or '']
|
||||
p.all_seeds = [seed]
|
||||
p.all_subseeds = [-1]
|
||||
p.scripts = None
|
||||
p.is_control = False
|
||||
p.do_not_save_samples = True
|
||||
p.do_not_save_grid = True
|
||||
return p
|
||||
|
||||
def change_mode(self, dropdown, text):
|
||||
self.ui_mode = not self.ui_mode
|
||||
if self.ui_mode:
|
||||
@@ -533,10 +578,16 @@ class YoloRestorer(Detailer):
|
||||
ui_mode.click(fn=self.change_mode, inputs=[detailers, detailers_text], outputs=[detailers, detailers_text, refresh_btn])
|
||||
with gr.Row():
|
||||
classes = gr.Textbox(label="Detailer classes", placeholder="Classes", elem_id=f"{tab}_detailer_classes")
|
||||
if tab == 'extras': # Process tab is standalone, there is no base prompt to fall back to
|
||||
prompt_placeholder = 'detailer prompt, leave empty for none'
|
||||
negative_placeholder = 'detailer negative prompt, leave empty for none'
|
||||
else:
|
||||
prompt_placeholder = 'detailer prompt or leave empty to use main prompt'
|
||||
negative_placeholder = 'detailer prompt or leave empty to use main prompt'
|
||||
with gr.Row():
|
||||
prompt = gr.Textbox(label="Detailer prompt", value='', placeholder='detailer prompt or leave empty to use main prompt', lines=2, elem_id=f"{tab}_detailer_prompt", elem_classes=["prompt"])
|
||||
prompt = gr.Textbox(label="Detailer prompt", value='', placeholder=prompt_placeholder, lines=2, elem_id=f"{tab}_detailer_prompt", elem_classes=["prompt"])
|
||||
with gr.Row():
|
||||
negative = gr.Textbox(label="Detailer negative prompt", value='', placeholder='detailer prompt or leave empty to use main prompt', lines=2, elem_id=f"{tab}_detailer_negative", elem_classes=["prompt"])
|
||||
negative = gr.Textbox(label="Detailer negative prompt", value='', placeholder=negative_placeholder, lines=2, elem_id=f"{tab}_detailer_negative", elem_classes=["prompt"])
|
||||
with gr.Row():
|
||||
steps = gr.Slider(label="Detailer steps", elem_id=f"{tab}_detailer_steps", value=10, minimum=0, maximum=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)
|
||||
@@ -557,6 +608,23 @@ class YoloRestorer(Detailer):
|
||||
with gr.Row(elem_classes=['flex-break']):
|
||||
renoise_value = gr.Slider(minimum=0.5, maximum=1.5, step=0.01, label='Renoise', value=shared.opts.detailer_sigma_adjust, elem_id=f"{tab}_detailer_renoise")
|
||||
renoise_end = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Renoise end', value=shared.opts.detailer_sigma_adjust_max, elem_id=f"{tab}_detailer_renoise_end")
|
||||
sampler_block = None
|
||||
if tab == 'extras': # fold the standalone sampler settings into the detailer accordion; values applied per-job in make_processing, never global opts
|
||||
from modules import sd_samplers
|
||||
sd_samplers.set_samplers()
|
||||
sampler_choices = [s.name for s in sd_samplers.samplers if s.name != 'Same as primary']
|
||||
with gr.Accordion('Sampler', open=False, elem_id=f"{tab}_detailer_sampler_accordion", elem_classes=["small-accordion"]):
|
||||
with gr.Row():
|
||||
d_sampler = gr.Dropdown(label='Sampling method', choices=sampler_choices, value='Default', elem_id=f"{tab}_detailer_sampler")
|
||||
d_prediction = gr.Dropdown(label='Prediction method', choices=['default', 'epsilon', 'sample', 'v_prediction', 'flow_prediction'], value='default', elem_id=f"{tab}_detailer_prediction")
|
||||
with gr.Row():
|
||||
d_shift = gr.Slider(label='Flow shift', minimum=0, maximum=10, step=0.1, value=shared.opts.schedulers_shift, elem_id=f"{tab}_detailer_shift")
|
||||
d_cfg = gr.Slider(label='Guidance scale', minimum=0, maximum=30, step=0.1, value=6.0, elem_id=f"{tab}_detailer_cfg")
|
||||
with gr.Row():
|
||||
d_options = gr.CheckboxGroup(label='Options', choices=['low order', 'thresholding', 'dynamic', 'rescale'], value=['low order'], elem_id=f"{tab}_detailer_options")
|
||||
with gr.Row():
|
||||
d_seed = gr.Number(label='Seed', value=-1, precision=0, elem_id=f"{tab}_detailer_seed")
|
||||
sampler_block = {'sampler': d_sampler, 'prediction': d_prediction, 'shift': d_shift, 'cfg_scale': d_cfg, 'options': d_options, 'seed': d_seed}
|
||||
|
||||
merge.change(fn=ui_settings_change, inputs=[merge, detailers, detailers_text, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps, renoise_value, renoise_end, resolution, save, sort, seg], outputs=[])
|
||||
detailers.change(fn=ui_settings_change, inputs=[merge, detailers, detailers_text, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps, renoise_value, renoise_end, resolution, save, sort, seg], outputs=[])
|
||||
@@ -573,6 +641,8 @@ class YoloRestorer(Detailer):
|
||||
save.change(fn=ui_settings_change, inputs=[merge, detailers, detailers_text, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps, renoise_value, renoise_end, resolution, save, sort, seg], outputs=[])
|
||||
sort.change(fn=ui_settings_change, inputs=[merge, detailers, detailers_text, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps, renoise_value, renoise_end, resolution, save, sort, seg], outputs=[])
|
||||
seg.change(fn=ui_settings_change, inputs=[merge, detailers, detailers_text, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou, steps, renoise_value, renoise_end, resolution, save, sort, seg], outputs=[])
|
||||
if tab == 'extras':
|
||||
return enabled, prompt, negative, steps, strength, resolution, sampler_block
|
||||
return enabled, prompt, negative, steps, strength, resolution
|
||||
|
||||
|
||||
|
||||
@@ -100,10 +100,10 @@ def run_postprocessing(extras_mode, image, image_folder: list[tempfile.NamedTemp
|
||||
return outputs, info, params
|
||||
|
||||
|
||||
def run_extras(extras_mode, resize_mode, image, image_folder, input_dir, output_dir, show_extras_results, upscaling_resize, upscaling_resize_w, upscaling_resize_h, upscaling_crop, extras_upscaler_1, extras_upscaler_2, extras_upscaler_2_visibility, save_output: bool = True):
|
||||
def run_extras(extras_mode, resize_mode, image, image_folder, input_dir, output_dir, show_extras_results, upscaling_resize, upscaling_resize_w, upscaling_resize_h, upscaling_crop, extras_upscaler_1, extras_upscaler_2, extras_upscaler_2_visibility, save_output: bool = True, script_args: dict | None = None):
|
||||
"""old handler for API"""
|
||||
|
||||
args = scripts_manager.scripts_postproc.create_args_for_run({
|
||||
merged = {
|
||||
"Upscale": {
|
||||
"upscale_mode": resize_mode,
|
||||
"upscale_by": upscaling_resize,
|
||||
@@ -114,6 +114,10 @@ def run_extras(extras_mode, resize_mode, image, image_folder, input_dir, output_
|
||||
"upscaler_2_name": extras_upscaler_2,
|
||||
"upscaler_2_visibility": extras_upscaler_2_visibility,
|
||||
},
|
||||
})
|
||||
}
|
||||
if script_args:
|
||||
for name, kvs in script_args.items():
|
||||
merged.setdefault(name, {}).update(kvs or {})
|
||||
args = scripts_manager.scripts_postproc.create_args_for_run(merged)
|
||||
|
||||
return run_postprocessing(extras_mode, image, image_folder, input_dir, output_dir, show_extras_results, *args, save_output=save_output)
|
||||
|
||||
@@ -118,11 +118,11 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No
|
||||
args["Hires steps"] = p.hr_second_pass_steps
|
||||
args["Hires strength"] = p.hr_denoising_strength
|
||||
args["Hires sampler"] = p.hr_sampler_name if p.hr_sampler_name != 'Default' else None
|
||||
args["Hires CFG scale"] = p.cfg_image if p.cfg_image > -1 else None
|
||||
args["Hires CFG scale"] = p.cfg_image if (p.cfg_image is not None and p.cfg_image > -1) else None
|
||||
if 'refine' in p.ops:
|
||||
args["Refine"] = p.enable_hr
|
||||
args["Refiner"] = None if (not shared.opts.add_model_name_to_info) or (not shared.sd_refiner) or (not shared.sd_refiner.sd_checkpoint_info.model_name) else shared.sd_refiner.sd_checkpoint_info.model_name.replace(',', '').replace(':', '')
|
||||
args['Hires CFG scale'] = p.cfg_image if p.cfg_image > -1 else None
|
||||
args['Hires CFG scale'] = p.cfg_image if (p.cfg_image is not None and p.cfg_image > -1) else None
|
||||
args['Refiner steps'] = p.refiner_steps
|
||||
args['Refiner start'] = p.refiner_start
|
||||
args["Hires steps"] = p.hr_second_pass_steps
|
||||
@@ -130,7 +130,7 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No
|
||||
if ('img2img' in p.ops or 'inpaint' in p.ops) and ('txt2img' not in p.ops and 'hires' not in p.ops): # real img2img/inpaint
|
||||
args["Init image size"] = f"{getattr(p, 'init_img_width', 0)}x{getattr(p, 'init_img_height', 0)}"
|
||||
args["Init image hash"] = getattr(p, 'init_img_hash', None)
|
||||
args['Image CFG scale'] = p.cfg_image if p.cfg_image > -1 else None
|
||||
args['Image CFG scale'] = p.cfg_image if (p.cfg_image is not None and p.cfg_image > -1) else None
|
||||
args["Mask weight"] = getattr(p, "inpainting_mask_weight", shared.opts.inpainting_mask_weight) if p.is_using_inpainting_conditioning else None
|
||||
args["Denoising strength"] = getattr(p, 'denoising_strength', None)
|
||||
if args["Size"] != args["Init image size"]:
|
||||
|
||||
Reference in New Issue
Block a user