diff --git a/modules/api/api.py b/modules/api/api.py index 1f60e5c01..a3dabb9de 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -260,8 +260,31 @@ class Api: p.per_script_args[alwayson_script.title()] = request.alwayson_scripts[alwayson_script_name]["args"] return script_args + def prepare_img_gen_request(self, request, img_gen_type: str): + if hasattr(request, "face_id") and request.face_id and not request.script_name and "FaceID" not in request.alwayson_scripts: + request.script_name = "FaceID" + request.script_args = [request.face_id.scale, request.face_id.image] + del request.face_id + + if hasattr(request, "ip_adapter") and request.ip_adapter and request.script_name != "IP Adapter" and "IP Adapter" not in request.alwayson_scripts: + request.alwayson_scripts = {} if request.alwayson_scripts is None else request.alwayson_scripts + request.alwayson_scripts["IP Adapter"] = { + "args": [request.ip_adapter.adapter, request.ip_adapter.scale, request.ip_adapter.image] + } + del request.ip_adapter + + def sanitize_img_gen_request(self, request, img_gen_type: str): + if hasattr(request, "alwayson_scripts") and request.alwayson_scripts and "IP Adapter" in request.alwayson_scripts: + # Avoid returning the same base64 ipadapter input image in the response + request.alwayson_scripts["IP Adapter"]["args"][2] = "" + + if hasattr(request, "script_name") and request.script_name == "FaceID": + # Avoid returning the same base64 FaceID input image in the response + request.script_args[1] = "" def text2imgapi(self, txt2imgreq: models.StableDiffusionTxt2ImgProcessingAPI): + self.prepare_img_gen_request(txt2imgreq, "txt2img") + script_runner = scripts.scripts_txt2img if not script_runner.scripts: script_runner.initialize_scripts(False) @@ -279,6 +302,8 @@ class Api: args = vars(populate) args.pop('script_name', None) args.pop('script_args', None) # will refeed them to the pipeline directly after initializing them + args.pop('face_id', None) + args.pop('ip_adapter', None) args.pop('alwayson_scripts', None) send_images = args.pop('send_images', True) args.pop('save_images', None) @@ -298,9 +323,12 @@ class Api: shared.state.end(api=False) b64images = list(map(encode_pil_to_base64, processed.images)) if send_images else [] + self.sanitize_img_gen_request(txt2imgreq, "txt2img") return models.TextToImageResponse(images=b64images, parameters=vars(txt2imgreq), info=processed.js()) def img2imgapi(self, img2imgreq: models.StableDiffusionImg2ImgProcessingAPI): + self.prepare_img_gen_request(img2imgreq, "img2img") + init_images = img2imgreq.init_images if init_images is None: raise HTTPException(status_code=404, detail="Init image not found") @@ -327,6 +355,8 @@ class Api: args.pop('script_name', None) args.pop('script_args', None) # will refeed them to the pipeline directly after initializing them args.pop('alwayson_scripts', None) + args.pop('face_id', None) + args.pop('ip_adapter', None) send_images = args.pop('send_images', True) args.pop('save_images', None) @@ -349,6 +379,7 @@ class Api: if not img2imgreq.include_init_images: img2imgreq.init_images = None img2imgreq.mask = None + self.sanitize_img_gen_request(img2imgreq, "img2img") return models.ImageToImageResponse(images=b64images, parameters=vars(img2imgreq), info=processed.js()) def extras_single_image_api(self, req: models.ExtrasSingleImageRequest): diff --git a/modules/api/models.py b/modules/api/models.py index 9d90f0ca7..17819d0b6 100644 --- a/modules/api/models.py +++ b/modules/api/models.py @@ -91,6 +91,18 @@ class PydanticModelGenerator: DynamicModel.__config__.allow_mutation = True return DynamicModel + +class IPAdapterItem(BaseModel): + adapter: str = Field(title="Adapter", default="Base", description="Adapter to use") + image: str = Field(title="Image", default="", description="Adapter image, must be a Base64 string containing the image's data.") + scale: float = Field(title="Scale", default=0.5, gt=0, le=1, description="Scale of the adapter image, must be between 0 and 1.") + + +class FaceIDItem(BaseModel): + image: str = Field(title="Image", default="", description="Source face image, must be a Base64 string containing the image's data.") + scale: float = Field(title="Scale", default=0.5, gt=0, le=1, description="Scale of the source face, must be between 0 and 1.") + + StableDiffusionTxt2ImgProcessingAPI = PydanticModelGenerator( "StableDiffusionProcessingTxt2Img", StableDiffusionProcessingTxt2Img, @@ -101,6 +113,8 @@ StableDiffusionTxt2ImgProcessingAPI = PydanticModelGenerator( {"key": "send_images", "type": bool, "default": True}, {"key": "save_images", "type": bool, "default": False}, {"key": "alwayson_scripts", "type": dict, "default": {}}, + {"key": "ip_adapter", "type": Optional[IPAdapterItem], "default": None, "exclude": True}, + {"key": "face_id", "type": Optional[FaceIDItem], "default": None, "exclude": True}, ] ).generate_model() @@ -112,12 +126,14 @@ StableDiffusionImg2ImgProcessingAPI = PydanticModelGenerator( {"key": "init_images", "type": list, "default": None}, {"key": "denoising_strength", "type": float, "default": 0.75}, {"key": "mask", "type": str, "default": None}, - {"key": "include_init_images", "type": bool, "default": False, "exclude" : True}, + {"key": "include_init_images", "type": bool, "default": False, "exclude": True}, {"key": "script_name", "type": str, "default": None}, {"key": "script_args", "type": list, "default": []}, {"key": "send_images", "type": bool, "default": True}, {"key": "save_images", "type": bool, "default": False}, {"key": "alwayson_scripts", "type": dict, "default": {}}, + {"key": "ip_adapter", "type": Optional[IPAdapterItem], "default": None, "exclude": True}, + {"key": "face_id", "type": Optional[FaceIDItem], "default": None, "exclude": True}, ] ).generate_model()