|
|
from typing import Any |
|
|
from fastapi import FastAPI, Body |
|
|
from pydantic import BaseModel |
|
|
import modules.script_callbacks as script_callbacks |
|
|
from modules import shared |
|
|
from modules.api.api import encode_pil_to_base64, decode_base64_to_image |
|
|
from modules.call_queue import queue_lock |
|
|
from replacer.generate import generate |
|
|
from replacer.generation_args import GenerationArgs, HiresFixArgs |
|
|
from replacer.tools import generateSeed |
|
|
from replacer.ui.tools_ui import IS_WEBUI_1_9, prepareExpectedUIBehavior |
|
|
from replacer.extensions import replacer_extensions |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def replacer_api(_, app: FastAPI): |
|
|
from scripts.sam import sam_model_list |
|
|
from scripts.dino import dino_model_list |
|
|
try: |
|
|
from lama_cleaner_masked_content.inpaint import lamaInpaint |
|
|
lama_cleaner_available = True |
|
|
except Exception as e: |
|
|
lama_cleaner_available = False |
|
|
|
|
|
class ReplaceRequest(BaseModel): |
|
|
input_image: str = "base64 image" |
|
|
detection_prompt: str = "" |
|
|
avoidance_prompt: str = "" |
|
|
positive_prompt: str = "" |
|
|
negative_prompt: str = "" |
|
|
width: int = 512 |
|
|
height: int = 512 |
|
|
sam_model_name: str = sam_model_list[0] if sam_model_list else "" |
|
|
dino_model_name: str = dino_model_list[0] |
|
|
seed: int = -1 |
|
|
sampler: str = "DPM++ 2M SDE" if IS_WEBUI_1_9 else "DPM++ 2M SDE Karras" |
|
|
scheduler: str = "Automatic" |
|
|
steps: int = 20 |
|
|
box_threshold: float = 0.3 |
|
|
mask_expand: int = 35 |
|
|
mask_blur: int = 4 |
|
|
mask_num: str = "Random" |
|
|
max_resolution_on_detection = 1280 |
|
|
cfg_scale: float = 5.5 |
|
|
denoise: float = 1.0 |
|
|
inpaint_padding = 40 |
|
|
inpainting_mask_invert: bool = False |
|
|
upscaler_for_img2img : str = "" |
|
|
fix_steps : bool = False |
|
|
inpainting_fill : int = 0 |
|
|
sd_model_checkpoint : str = "" |
|
|
clip_skip: int = 1 |
|
|
rotation_fix: str = '-' |
|
|
extra_include: list = ["mask", "box", "cut", "preview", "script"] |
|
|
variation_seed: int = -1 |
|
|
variation_strength: float = 0.0 |
|
|
integer_only_masked: bool = False |
|
|
forbid_too_small_crop_region: bool = True |
|
|
correct_aspect_ratio: bool = True |
|
|
|
|
|
use_hires_fix: bool = False |
|
|
hf_upscaler: str = "ESRGAN_4x" |
|
|
hf_steps: int = 4 |
|
|
hf_sampler: str = "Use same sampler" |
|
|
hf_scheduler: str = "Use same scheduler" |
|
|
hf_denoise: float = 0.35 |
|
|
hf_cfg_scale: float = 1.0 |
|
|
hf_positive_prompt_suffix: str = "<lora:lcm-lora-sdv1-5:1>" |
|
|
hf_size_limit: int = 1800 |
|
|
hf_above_limit_upscaler: str = "Lanczos" |
|
|
hf_unload_detection_models: bool = True |
|
|
hf_disable_cn: bool = True |
|
|
hf_extra_mask_expand: int = 5 |
|
|
hf_positive_prompt: str = "" |
|
|
hf_negative_prompt: str = "" |
|
|
hf_sd_model_checkpoint: str = "Use same checkpoint" |
|
|
hf_extra_inpaint_padding: int = 250 |
|
|
hf_extra_mask_blur: int = 2 |
|
|
hf_randomize_seed: bool = True |
|
|
hf_soft_inpaint: str = "Same" |
|
|
hf_supersampling: float = 1.6 |
|
|
|
|
|
scripts : dict = {} |
|
|
|
|
|
|
|
|
@app.post("/replacer/replace") |
|
|
async def api_replacer_replace(data: ReplaceRequest = Body(...)) -> Any: |
|
|
image = decode_base64_to_image(data.input_image).convert("RGBA") |
|
|
|
|
|
cn_args, soft_inpaint_args = replacer_extensions.prepareScriptsArgs_api(data.scripts) |
|
|
|
|
|
hires_fix_args = HiresFixArgs( |
|
|
upscaler = data.hf_upscaler, |
|
|
steps = data.hf_steps, |
|
|
sampler = data.hf_sampler, |
|
|
scheduler=data.hf_scheduler, |
|
|
denoise = data.hf_denoise, |
|
|
cfg_scale = data.hf_cfg_scale, |
|
|
positive_prompt_suffix = data.hf_positive_prompt_suffix, |
|
|
size_limit = data.hf_size_limit, |
|
|
above_limit_upscaler = data.hf_above_limit_upscaler, |
|
|
unload_detection_models = data.hf_unload_detection_models, |
|
|
disable_cn = data.hf_disable_cn, |
|
|
extra_mask_expand = data.hf_extra_mask_expand, |
|
|
positive_prompt = data.hf_positive_prompt, |
|
|
negative_prompt = data.hf_negative_prompt, |
|
|
sd_model_checkpoint = data.hf_sd_model_checkpoint, |
|
|
extra_inpaint_padding = data.hf_extra_inpaint_padding, |
|
|
extra_mask_blur = data.hf_extra_mask_blur, |
|
|
randomize_seed = data.hf_randomize_seed, |
|
|
soft_inpaint = data.hf_soft_inpaint, |
|
|
supersampling = data.hf_supersampling, |
|
|
) |
|
|
|
|
|
gArgs = GenerationArgs( |
|
|
positivePrompt=data.positive_prompt, |
|
|
negativePrompt=data.negative_prompt, |
|
|
detectionPrompt=data.detection_prompt, |
|
|
avoidancePrompt=data.avoidance_prompt, |
|
|
upscalerForImg2Img=data.upscaler_for_img2img, |
|
|
seed=data.seed, |
|
|
samModel=data.sam_model_name, |
|
|
grdinoModel=data.dino_model_name, |
|
|
boxThreshold=data.box_threshold, |
|
|
maskExpand=data.mask_expand, |
|
|
maxResolutionOnDetection=data.max_resolution_on_detection, |
|
|
|
|
|
steps=data.steps, |
|
|
sampler_name=data.sampler, |
|
|
scheduler=data.scheduler, |
|
|
mask_blur=data.mask_blur, |
|
|
inpainting_fill=data.inpainting_fill, |
|
|
batch_count=1, |
|
|
batch_size=1, |
|
|
cfg_scale=data.cfg_scale, |
|
|
denoising_strength=data.denoise, |
|
|
height=data.height, |
|
|
width=data.width, |
|
|
inpaint_full_res_padding=data.inpaint_padding, |
|
|
img2img_fix_steps=data.fix_steps, |
|
|
inpainting_mask_invert=data.inpainting_mask_invert, |
|
|
|
|
|
images=[image], |
|
|
override_sd_model=True, |
|
|
sd_model_checkpoint=data.sd_model_checkpoint, |
|
|
mask_num=data.mask_num, |
|
|
avoidance_mask=None, |
|
|
only_custom_mask=False, |
|
|
custom_mask=None, |
|
|
use_inpaint_diff=False, |
|
|
clip_skip=data.clip_skip, |
|
|
pass_into_hires_fix_automatically=data.use_hires_fix, |
|
|
save_before_hires_fix=False, |
|
|
do_not_use_mask=False, |
|
|
rotation_fix=data.rotation_fix, |
|
|
variation_seed=data.variation_seed, |
|
|
variation_strength=data.variation_strength, |
|
|
integer_only_masked=data.integer_only_masked, |
|
|
forbid_too_small_crop_region=data.forbid_too_small_crop_region, |
|
|
correct_aspect_ratio=data.correct_aspect_ratio, |
|
|
|
|
|
hires_fix_args=hires_fix_args, |
|
|
cn_args=cn_args, |
|
|
soft_inpaint_args=soft_inpaint_args, |
|
|
) |
|
|
prepareExpectedUIBehavior(gArgs) |
|
|
|
|
|
with queue_lock: |
|
|
shared.state.begin('api /replacer/replace') |
|
|
try: |
|
|
processed, allExtraImages = generate(gArgs, "", False, data.extra_include) |
|
|
finally: |
|
|
shared.state.end() |
|
|
|
|
|
return { |
|
|
"image": encode_pil_to_base64(processed.images[0]).decode(), |
|
|
"extra_images": [encode_pil_to_base64(x).decode() for x in allExtraImages], |
|
|
"info": processed.info, |
|
|
"json": processed.js(), |
|
|
} |
|
|
|
|
|
|
|
|
@app.post("/replacer/available_options") |
|
|
async def api_replacer_available_options() -> Any: |
|
|
return { |
|
|
"sam_model_name": sam_model_list, |
|
|
"dino_model_name": dino_model_list, |
|
|
"upscalers": [""] + [x.name for x in shared.sd_upscalers], |
|
|
"lama_cleaner_available": lama_cleaner_available, |
|
|
"available_scripts": replacer_extensions.getAvailableScripts_api(), |
|
|
} |
|
|
|
|
|
|
|
|
script_callbacks.on_app_started(replacer_api) |
|
|
|
|
|
|