2022-10-23 18:35:49 +00:00
import inspect
2022-10-29 19:09:19 +00:00
from click import prompt
2022-10-17 07:02:08 +00:00
from pydantic import BaseModel , Field , create_model
2022-10-23 18:35:49 +00:00
from typing import Any , Optional
2022-10-23 02:13:32 +00:00
from typing_extensions import Literal
2022-10-23 18:35:49 +00:00
from inflection import underscore
2022-10-21 23:27:40 +00:00
from modules . processing import StableDiffusionProcessingTxt2Img , StableDiffusionProcessingImg2Img
2022-10-23 02:13:32 +00:00
from modules . shared import sd_upscalers
2022-10-17 07:02:08 +00:00
2022-10-17 19:10:36 +00:00
API_NOT_ALLOWED = [
" self " ,
" kwargs " ,
" sd_model " ,
" outpath_samples " ,
" outpath_grids " ,
" sampler_index " ,
" do_not_save_samples " ,
" do_not_save_grid " ,
" extra_generation_params " ,
" overlay_images " ,
" do_not_reload_embeddings " ,
" seed_enable_extras " ,
" prompt_for_display " ,
" sampler_noise_scheduler_override " ,
" ddim_discretize "
]
2022-10-17 07:02:08 +00:00
class ModelDef ( BaseModel ) :
""" Assistance Class for Pydantic Dynamic Model Generation """
field : str
field_alias : str
field_type : Any
field_value : Any
2022-10-24 15:16:07 +00:00
field_exclude : bool = False
2022-10-17 07:02:08 +00:00
2022-10-17 19:10:36 +00:00
class PydanticModelGenerator :
2022-10-17 07:02:08 +00:00
"""
2022-10-17 07:18:41 +00:00
Takes in created classes and stubs them out in a way FastAPI / Pydantic is happy about :
source_data is a snapshot of the default values produced by the class
params are the names of the actual keys required by __init__
2022-10-17 07:02:08 +00:00
"""
def __init__ (
self ,
model_name : str = None ,
2022-10-18 19:04:56 +00:00
class_instance = None ,
additional_fields = None ,
2022-10-17 07:02:08 +00:00
) :
2022-10-17 19:10:36 +00:00
def field_type_generator ( k , v ) :
# field_type = str if not overrides.get(k) else overrides[k]["type"]
# print(k, v.annotation, v.default)
field_type = v . annotation
2022-10-29 19:45:29 +00:00
2022-10-17 07:02:08 +00:00
return Optional [ field_type ]
2022-10-29 19:45:29 +00:00
2022-10-17 19:10:36 +00:00
def merge_class_params ( class_ ) :
all_classes = list ( filter ( lambda x : x is not object , inspect . getmro ( class_ ) ) )
parameters = { }
for classes in all_classes :
parameters = { * * parameters , * * inspect . signature ( classes . __init__ ) . parameters }
return parameters
2022-10-29 19:45:29 +00:00
2022-10-17 07:02:08 +00:00
self . _model_name = model_name
2022-10-17 19:10:36 +00:00
self . _class_data = merge_class_params ( class_instance )
2022-10-17 07:02:08 +00:00
self . _model_def = [
ModelDef (
field = underscore ( k ) ,
field_alias = k ,
2022-10-17 19:10:36 +00:00
field_type = field_type_generator ( k , v ) ,
2022-10-24 16:18:54 +00:00
field_value = v . default
2022-10-17 07:02:08 +00:00
)
2022-10-17 19:10:36 +00:00
for ( k , v ) in self . _class_data . items ( ) if k not in API_NOT_ALLOWED
2022-10-17 07:02:08 +00:00
]
2022-10-29 19:45:29 +00:00
2022-10-18 19:04:56 +00:00
for fields in additional_fields :
self . _model_def . append ( ModelDef (
2022-10-29 19:45:29 +00:00
field = underscore ( fields [ " key " ] ) ,
field_alias = fields [ " key " ] ,
2022-10-18 19:04:56 +00:00
field_type = fields [ " type " ] ,
2022-10-24 15:16:07 +00:00
field_value = fields [ " default " ] ,
field_exclude = fields [ " exclude " ] if " exclude " in fields else False ) )
2022-10-17 07:02:08 +00:00
def generate_model ( self ) :
"""
Creates a pydantic BaseModel
from the json and overrides provided at initialization
"""
fields = {
2022-10-24 15:16:07 +00:00
d . field : ( d . field_type , Field ( default = d . field_value , alias = d . field_alias , exclude = d . field_exclude ) ) for d in self . _model_def
2022-10-17 07:02:08 +00:00
}
DynamicModel = create_model ( self . _model_name , * * fields )
DynamicModel . __config__ . allow_population_by_field_name = True
2022-10-17 19:10:36 +00:00
DynamicModel . __config__ . allow_mutation = True
2022-10-17 07:02:08 +00:00
return DynamicModel
2022-10-29 19:45:29 +00:00
2022-10-21 23:27:40 +00:00
StableDiffusionTxt2ImgProcessingAPI = PydanticModelGenerator (
2022-10-29 19:45:29 +00:00
" StableDiffusionProcessingTxt2Img " ,
2022-10-18 19:04:56 +00:00
StableDiffusionProcessingTxt2Img ,
2022-10-19 05:19:01 +00:00
[ { " key " : " sampler_index " , " type " : str , " default " : " Euler " } ]
2022-10-21 23:27:40 +00:00
) . generate_model ( )
StableDiffusionImg2ImgProcessingAPI = PydanticModelGenerator (
2022-10-29 19:45:29 +00:00
" StableDiffusionProcessingImg2Img " ,
2022-10-21 23:27:40 +00:00
StableDiffusionProcessingImg2Img ,
2022-10-24 15:16:07 +00:00
[ { " key " : " sampler_index " , " type " : str , " default " : " Euler " } , { " 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 } ]
2022-10-23 18:35:49 +00:00
) . generate_model ( )
2022-10-22 23:24:04 +00:00
class TextToImageResponse ( BaseModel ) :
images : list [ str ] = Field ( default = None , title = " Image " , description = " The generated image in base64 format. " )
2022-10-23 18:35:49 +00:00
parameters : dict
info : str
class ImageToImageResponse ( BaseModel ) :
images : list [ str ] = Field ( default = None , title = " Image " , description = " The generated image in base64 format. " )
parameters : dict
2022-10-23 18:13:37 +00:00
info : str
2022-10-22 23:24:04 +00:00
2022-10-23 02:13:32 +00:00
class ExtrasBaseRequest ( BaseModel ) :
resize_mode : Literal [ 0 , 1 ] = Field ( default = 0 , title = " Resize Mode " , description = " Sets the resize mode: 0 to upscale by upscaling_resize amount, 1 to upscale up to upscaling_resize_h x upscaling_resize_w. " )
show_extras_results : bool = Field ( default = True , title = " Show results " , description = " Should the backend return the generated image? " )
gfpgan_visibility : float = Field ( default = 0 , title = " GFPGAN Visibility " , ge = 0 , le = 1 , allow_inf_nan = False , description = " Sets the visibility of GFPGAN, values should be between 0 and 1. " )
codeformer_visibility : float = Field ( default = 0 , title = " CodeFormer Visibility " , ge = 0 , le = 1 , allow_inf_nan = False , description = " Sets the visibility of CodeFormer, values should be between 0 and 1. " )
codeformer_weight : float = Field ( default = 0 , title = " CodeFormer Weight " , ge = 0 , le = 1 , allow_inf_nan = False , description = " Sets the weight of CodeFormer, values should be between 0 and 1. " )
upscaling_resize : float = Field ( default = 2 , title = " Upscaling Factor " , ge = 1 , le = 4 , description = " By how much to upscale the image, only used when resize_mode=0. " )
upscaling_resize_w : int = Field ( default = 512 , title = " Target Width " , ge = 1 , description = " Target width for the upscaler to hit. Only used when resize_mode=1. " )
upscaling_resize_h : int = Field ( default = 512 , title = " Target Height " , ge = 1 , description = " Target height for the upscaler to hit. Only used when resize_mode=1. " )
upscaling_crop : bool = Field ( default = True , title = " Crop to fit " , description = " Should the upscaler crop the image to fit in the choosen size? " )
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 sd_upscalers ] ) } " )
upscaler_2 : str = Field ( default = " None " , title = " Secondary 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 sd_upscalers ] ) } " )
extras_upscaler_2_visibility : float = Field ( default = 0 , title = " Secondary upscaler visibility " , ge = 0 , le = 1 , allow_inf_nan = False , description = " Sets the visibility of secondary upscaler, values should be between 0 and 1. " )
class ExtraBaseResponse ( BaseModel ) :
2022-10-23 19:03:30 +00:00
html_info : str = Field ( title = " HTML info " , description = " A series of HTML tags containing the process info. " )
2022-10-23 02:13:32 +00:00
class ExtrasSingleImageRequest ( ExtrasBaseRequest ) :
image : str = Field ( default = " " , title = " Image " , description = " Image to work on, must be a Base64 string containing the image ' s data. " )
class ExtrasSingleImageResponse ( ExtraBaseResponse ) :
2022-10-23 16:07:59 +00:00
image : str = Field ( default = None , title = " Image " , description = " The generated image in base64 format. " )
2022-10-24 11:32:18 +00:00
class FileData ( BaseModel ) :
data : str = Field ( title = " File data " , description = " Base64 representation of the file " )
name : str = Field ( title = " File name " )
2022-10-23 16:07:59 +00:00
class ExtrasBatchImagesRequest ( ExtrasBaseRequest ) :
2022-10-24 11:32:18 +00:00
imageList : list [ FileData ] = Field ( title = " Images " , description = " List of images to work on. Must be Base64 strings " )
2022-10-23 16:07:59 +00:00
class ExtrasBatchImagesResponse ( ExtraBaseResponse ) :
2022-10-29 19:45:29 +00:00
images : list [ str ] = Field ( title = " Images " , description = " The generated images in base64 format. " )
2022-10-29 19:09:19 +00:00
class PNGInfoRequest ( BaseModel ) :
image : str = Field ( title = " Image " , description = " The base64 encoded PNG image " )
class PNGInfoResponse ( BaseModel ) :
2022-10-29 19:47:24 +00:00
info : str = Field ( title = " Image info " , description = " A string with all the info the image had " )
2022-10-29 19:45:29 +00:00
class ProgressResponse ( BaseModel ) :
progress : float
eta_relative : float
state : dict