2022-10-23 12:35:49 -06:00
import inspect
2023-07-18 02:48:40 -06:00
2022-10-17 01:02:08 -06:00
from pydantic import BaseModel , Field , create_model
2023-08-25 01:58:19 -06:00
from typing import Any , Optional , Literal
2022-10-23 12:35:49 -06:00
from inflection import underscore
2022-10-21 17:27:40 -06:00
from modules . processing import StableDiffusionProcessingTxt2Img , StableDiffusionProcessingImg2Img
2022-11-02 21:51:22 -06:00
from modules . shared import sd_upscalers , opts , parser
2022-10-17 01:02:08 -06:00
2022-10-17 13:10:36 -06:00
API_NOT_ALLOWED = [
" self " ,
" kwargs " ,
" sd_model " ,
" outpath_samples " ,
" outpath_grids " ,
" sampler_index " ,
2023-03-03 06:29:10 -07:00
# "do_not_save_samples",
# "do_not_save_grid",
2022-10-17 13:10:36 -06:00
" extra_generation_params " ,
" overlay_images " ,
" do_not_reload_embeddings " ,
" seed_enable_extras " ,
" prompt_for_display " ,
" sampler_noise_scheduler_override " ,
" ddim_discretize "
]
2022-10-17 01:02:08 -06: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 09:16:07 -06:00
field_exclude : bool = False
2022-10-17 01:02:08 -06:00
2022-10-17 13:10:36 -06:00
class PydanticModelGenerator :
2022-10-17 01:02:08 -06:00
"""
2022-10-17 01:18:41 -06: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 01:02:08 -06:00
"""
def __init__ (
self ,
model_name : str = None ,
2022-10-18 13:04:56 -06:00
class_instance = None ,
additional_fields = None ,
2022-10-17 01:02:08 -06:00
) :
2022-10-17 13:10:36 -06:00
def field_type_generator ( k , v ) :
field_type = v . annotation
2022-10-29 13:45:29 -06:00
2023-08-14 00:48:40 -06:00
if field_type == ' Image ' :
# images are sent as base64 strings via API
field_type = ' str '
2022-10-17 01:02:08 -06:00
return Optional [ field_type ]
2022-10-29 13:45:29 -06:00
2022-10-17 13:10:36 -06: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 13:45:29 -06:00
2022-10-17 01:02:08 -06:00
self . _model_name = model_name
2022-10-31 09:50:33 -06:00
self . _class_data = merge_class_params ( class_instance )
2022-10-27 13:20:15 -06:00
2022-10-17 01:02:08 -06:00
self . _model_def = [
ModelDef (
field = underscore ( k ) ,
field_alias = k ,
2022-10-17 13:10:36 -06:00
field_type = field_type_generator ( k , v ) ,
2023-08-14 00:48:40 -06:00
field_value = None if isinstance ( v . default , property ) else v . default
2022-10-17 01:02:08 -06:00
)
2022-10-17 13:10:36 -06:00
for ( k , v ) in self . _class_data . items ( ) if k not in API_NOT_ALLOWED
2022-10-17 01:02:08 -06:00
]
2022-10-29 13:45:29 -06:00
2022-10-18 13:04:56 -06:00
for fields in additional_fields :
self . _model_def . append ( ModelDef (
2022-10-29 13:45:29 -06:00
field = underscore ( fields [ " key " ] ) ,
field_alias = fields [ " key " ] ,
2022-10-18 13:04:56 -06:00
field_type = fields [ " type " ] ,
2022-10-24 09:16:07 -06:00
field_value = fields [ " default " ] ,
field_exclude = fields [ " exclude " ] if " exclude " in fields else False ) )
2022-10-17 01:02:08 -06:00
def generate_model ( self ) :
"""
Creates a pydantic BaseModel
from the json and overrides provided at initialization
"""
fields = {
2022-10-24 09:16:07 -06: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 01:02:08 -06:00
}
DynamicModel = create_model ( self . _model_name , * * fields )
DynamicModel . __config__ . allow_population_by_field_name = True
2022-10-17 13:10:36 -06:00
DynamicModel . __config__ . allow_mutation = True
2022-10-17 01:02:08 -06:00
return DynamicModel
2022-10-29 13:45:29 -06:00
2022-10-21 17:27:40 -06:00
StableDiffusionTxt2ImgProcessingAPI = PydanticModelGenerator (
2022-10-29 13:45:29 -06:00
" StableDiffusionProcessingTxt2Img " ,
2022-10-18 13:04:56 -06:00
StableDiffusionProcessingTxt2Img ,
2023-03-03 07:00:52 -07:00
[
{ " key " : " sampler_index " , " type " : str , " default " : " Euler " } ,
{ " key " : " script_name " , " type " : str , " default " : None } ,
{ " key " : " script_args " , " type " : list , " default " : [ ] } ,
2023-03-11 03:22:59 -07:00
{ " key " : " send_images " , " type " : bool , " default " : True } ,
{ " key " : " save_images " , " type " : bool , " default " : False } ,
2023-03-11 10:33:35 -07:00
{ " key " : " alwayson_scripts " , " type " : dict , " default " : { } } ,
2023-12-15 01:57:17 -07:00
{ " key " : " force_task_id " , " type " : str , " default " : None } ,
2023-12-17 00:22:03 -07:00
{ " key " : " infotext " , " type " : str , " default " : None } ,
2023-03-03 07:00:52 -07:00
]
2022-10-21 17:27:40 -06:00
) . generate_model ( )
StableDiffusionImg2ImgProcessingAPI = PydanticModelGenerator (
2022-10-29 13:45:29 -06:00
" StableDiffusionProcessingImg2Img " ,
2022-10-21 17:27:40 -06:00
StableDiffusionProcessingImg2Img ,
2023-03-03 07:00:52 -07: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 } ,
{ " key " : " script_name " , " type " : str , " default " : None } ,
{ " key " : " script_args " , " type " : list , " default " : [ ] } ,
2023-03-11 03:22:59 -07:00
{ " key " : " send_images " , " type " : bool , " default " : True } ,
{ " key " : " save_images " , " type " : bool , " default " : False } ,
2023-03-11 10:33:35 -07:00
{ " key " : " alwayson_scripts " , " type " : dict , " default " : { } } ,
2023-12-15 01:57:17 -07:00
{ " key " : " force_task_id " , " type " : str , " default " : None } ,
2023-12-17 00:22:03 -07:00
{ " key " : " infotext " , " type " : str , " default " : None } ,
2023-03-03 07:00:52 -07:00
]
2022-10-27 13:20:15 -06:00
) . generate_model ( )
2022-10-22 17:24:04 -06:00
class TextToImageResponse ( BaseModel ) :
2023-08-25 01:58:19 -06:00
images : list [ str ] = Field ( default = None , title = " Image " , description = " The generated image in base64 format. " )
2022-10-23 12:35:49 -06:00
parameters : dict
info : str
class ImageToImageResponse ( BaseModel ) :
2023-08-25 01:58:19 -06:00
images : list [ str ] = Field ( default = None , title = " Image " , description = " The generated image in base64 format. " )
2022-10-23 12:35:49 -06:00
parameters : dict
2022-10-23 12:13:37 -06:00
info : str
2022-10-22 17:24:04 -06:00
2022-10-22 20:13:32 -06: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. " )
2023-01-06 15:00:12 -07:00
upscaling_resize : float = Field ( default = 2 , title = " Upscaling Factor " , ge = 1 , le = 8 , description = " By how much to upscale the image, only used when resize_mode=0. " )
2022-10-22 20:13:32 -06:00
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. " )
2022-12-14 19:01:32 -07:00
upscaling_crop : bool = Field ( default = True , title = " Crop to fit " , description = " Should the upscaler crop the image to fit in the chosen size? " )
2022-10-22 20:13:32 -06:00
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. " )
2022-11-03 18:35:18 -06:00
upscale_first : bool = Field ( default = False , title = " Upscale first " , description = " Should the upscaler run before restoring faces? " )
2022-10-22 20:13:32 -06:00
class ExtraBaseResponse ( BaseModel ) :
2022-10-23 13:03:30 -06:00
html_info : str = Field ( title = " HTML info " , description = " A series of HTML tags containing the process info. " )
2022-10-22 20:13:32 -06: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 10:07:59 -06:00
image : str = Field ( default = None , title = " Image " , description = " The generated image in base64 format. " )
2022-10-24 05:32:18 -06: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 10:07:59 -06:00
class ExtrasBatchImagesRequest ( ExtrasBaseRequest ) :
2023-08-25 01:58:19 -06:00
imageList : list [ FileData ] = Field ( title = " Images " , description = " List of images to work on. Must be Base64 strings " )
2022-10-23 10:07:59 -06:00
class ExtrasBatchImagesResponse ( ExtraBaseResponse ) :
2023-08-25 01:58:19 -06:00
images : list [ str ] = Field ( title = " Images " , description = " The generated images in base64 format. " )
2022-10-29 13:45:29 -06:00
2022-10-29 13:09:19 -06:00
class PNGInfoRequest ( BaseModel ) :
image : str = Field ( title = " Image " , description = " The base64 encoded PNG image " )
class PNGInfoResponse ( BaseModel ) :
2023-01-04 13:36:30 -07:00
info : str = Field ( title = " Image info " , description = " A string with the parameters used to generate the image " )
2023-08-25 21:52:18 -06:00
items : dict = Field ( title = " Items " , description = " A dictionary containing all the other fields the image had " )
parameters : dict = Field ( title = " Parameters " , description = " A dictionary with parsed generation info fields " )
2022-10-29 13:47:24 -06:00
2022-10-29 16:03:32 -06:00
class ProgressRequest ( BaseModel ) :
skip_current_image : bool = Field ( default = False , title = " Skip current image " , description = " Skip current image serialization " )
2022-10-29 13:45:29 -06:00
class ProgressResponse ( BaseModel ) :
2022-10-29 13:55:43 -06:00
progress : float = Field ( title = " Progress " , description = " The progress with a range of 0 to 1 " )
eta_relative : float = Field ( title = " ETA in secs " )
2022-10-29 15:04:29 -06:00
state : dict = Field ( title = " State " , description = " The current state snapshot " )
2022-10-29 15:19:17 -06:00
current_image : str = Field ( default = None , title = " Current image " , description = " The current image in base64 format. opts.show_progress_every_n_steps is required for this to work. " )
2023-01-11 08:23:51 -07:00
textinfo : str = Field ( default = None , title = " Info text " , description = " Info text used by WebUI. " )
2022-10-31 09:45:52 -06:00
class InterrogateRequest ( BaseModel ) :
image : str = Field ( default = " " , title = " Image " , description = " Image to work on, must be a Base64 string containing the image ' s data. " )
2022-11-06 11:32:06 -07:00
model : str = Field ( default = " clip " , title = " Model " , description = " The interrogate model used. " )
2022-10-31 09:45:52 -06:00
class InterrogateResponse ( BaseModel ) :
caption : str = Field ( default = None , title = " Caption " , description = " The generated caption for the image. " )
2022-11-06 01:27:54 -07:00
2022-12-24 16:02:22 -07:00
class TrainResponse ( BaseModel ) :
info : str = Field ( title = " Train info " , description = " Response string from train embedding or hypernetwork task. " )
class CreateResponse ( BaseModel ) :
info : str = Field ( title = " Create info " , description = " Response string from create embedding or hypernetwork task. " )
2022-11-02 21:51:22 -06:00
fields = { }
2022-11-05 15:46:47 -06:00
for key , metadata in opts . data_labels . items ( ) :
value = opts . data . get ( key )
2023-07-26 01:47:12 -06:00
optType = opts . typemap . get ( type ( metadata . default ) , type ( metadata . default ) ) if metadata . default else Any
2022-11-02 21:51:22 -06:00
2023-07-26 01:47:12 -06:00
if metadata is not None :
2023-07-18 02:48:40 -06:00
fields . update ( { key : ( Optional [ optType ] , Field ( default = metadata . default , description = metadata . label ) ) } )
2022-11-02 21:51:22 -06:00
else :
fields . update ( { key : ( Optional [ optType ] , Field ( ) ) } )
OptionsModel = create_model ( " Options " , * * fields )
flags = { }
_options = vars ( parser ) [ ' _option_string_actions ' ]
for key in _options :
if ( _options [ key ] . dest != ' help ' ) :
flag = _options [ key ]
2022-11-04 21:38:24 -06:00
_type = str
2023-05-09 23:25:25 -06:00
if _options [ key ] . default is not None :
_type = type ( _options [ key ] . default )
flags . update ( { flag . dest : ( _type , Field ( default = flag . default , description = flag . help ) ) } )
2022-11-02 21:51:22 -06:00
FlagsModel = create_model ( " Flags " , * * flags )
class SamplerItem ( BaseModel ) :
name : str = Field ( title = " Name " )
2023-08-25 01:58:19 -06:00
aliases : list [ str ] = Field ( title = " Aliases " )
options : dict [ str , str ] = Field ( title = " Options " )
2022-11-02 21:51:22 -06:00
class UpscalerItem ( BaseModel ) :
name : str = Field ( title = " Name " )
2022-11-04 21:38:24 -06:00
model_name : Optional [ str ] = Field ( title = " Model Name " )
model_path : Optional [ str ] = Field ( title = " Path " )
2023-01-24 00:09:30 -07:00
model_url : Optional [ str ] = Field ( title = " URL " )
2023-01-24 00:05:45 -07:00
scale : Optional [ float ] = Field ( title = " Scale " )
2022-11-02 21:51:22 -06:00
2023-06-04 07:59:23 -06:00
class LatentUpscalerModeItem ( BaseModel ) :
name : str = Field ( title = " Name " )
2022-11-02 21:51:22 -06:00
class SDModelItem ( BaseModel ) :
title : str = Field ( title = " Title " )
model_name : str = Field ( title = " Model Name " )
2023-01-13 23:56:59 -07:00
hash : Optional [ str ] = Field ( title = " Short hash " )
sha256 : Optional [ str ] = Field ( title = " sha256 hash " )
2022-11-02 21:51:22 -06:00
filename : str = Field ( title = " Filename " )
2023-01-27 01:54:19 -07:00
config : Optional [ str ] = Field ( title = " Config file " )
2022-11-02 21:51:22 -06:00
2023-05-29 15:25:43 -06:00
class SDVaeItem ( BaseModel ) :
model_name : str = Field ( title = " Model Name " )
filename : str = Field ( title = " Filename " )
2022-11-02 21:51:22 -06:00
class HypernetworkItem ( BaseModel ) :
name : str = Field ( title = " Name " )
2022-11-04 21:38:24 -06:00
path : Optional [ str ] = Field ( title = " Path " )
2022-11-02 21:51:22 -06:00
class FaceRestorerItem ( BaseModel ) :
name : str = Field ( title = " Name " )
2022-11-04 21:38:24 -06:00
cmd_dir : Optional [ str ] = Field ( title = " Path " )
2022-11-02 21:51:22 -06:00
class RealesrganItem ( BaseModel ) :
name : str = Field ( title = " Name " )
2022-11-04 21:38:24 -06:00
path : Optional [ str ] = Field ( title = " Path " )
scale : Optional [ int ] = Field ( title = " Scale " )
2022-11-02 21:51:22 -06:00
class PromptStyleItem ( BaseModel ) :
name : str = Field ( title = " Name " )
2022-11-04 21:38:24 -06:00
prompt : Optional [ str ] = Field ( title = " Prompt " )
negative_prompt : Optional [ str ] = Field ( title = " Negative Prompt " )
2022-11-02 21:51:22 -06:00
2022-11-06 01:27:54 -07:00
2023-01-01 18:21:22 -07:00
class EmbeddingItem ( BaseModel ) :
step : Optional [ int ] = Field ( title = " Step " , description = " The number of steps that were used to train this embedding, if available " )
sd_checkpoint : Optional [ str ] = Field ( title = " SD Checkpoint " , description = " The hash of the checkpoint this embedding was trained on, if available " )
sd_checkpoint_name : Optional [ str ] = Field ( title = " SD Checkpoint Name " , description = " The name of the checkpoint this embedding was trained on, if available. Note that this is the name that was used by the trainer; for a stable identifier, use `sd_checkpoint` instead " )
shape : int = Field ( title = " Shape " , description = " The length of each individual vector in the embedding " )
vectors : int = Field ( title = " Vectors " , description = " The number of vectors in the embedding " )
2023-01-01 16:17:33 -07:00
class EmbeddingsResponse ( BaseModel ) :
2023-08-25 01:58:19 -06:00
loaded : dict [ str , EmbeddingItem ] = Field ( title = " Loaded " , description = " Embeddings loaded for the current model " )
skipped : dict [ str , EmbeddingItem ] = Field ( title = " Skipped " , description = " Embeddings skipped for the current model (likely due to architecture incompatibility) " )
2023-01-07 05:51:35 -07:00
class MemoryResponse ( BaseModel ) :
2023-01-09 19:23:58 -07:00
ram : dict = Field ( title = " RAM " , description = " System memory stats " )
cuda : dict = Field ( title = " CUDA " , description = " nVidia CUDA memory stats " )
2023-03-03 20:46:07 -07:00
2023-05-17 13:43:24 -06:00
2023-03-03 20:46:07 -07:00
class ScriptsList ( BaseModel ) :
2023-05-17 13:43:24 -06:00
txt2img : list = Field ( default = None , title = " Txt2img " , description = " Titles of scripts (txt2img) " )
img2img : list = Field ( default = None , title = " Img2img " , description = " Titles of scripts (img2img) " )
class ScriptArg ( BaseModel ) :
label : str = Field ( default = None , title = " Label " , description = " Name of the argument in UI " )
value : Optional [ Any ] = Field ( default = None , title = " Value " , description = " Default value of the argument " )
minimum : Optional [ Any ] = Field ( default = None , title = " Minimum " , description = " Minimum allowed value for the argumentin UI " )
maximum : Optional [ Any ] = Field ( default = None , title = " Minimum " , description = " Maximum allowed value for the argumentin UI " )
step : Optional [ Any ] = Field ( default = None , title = " Minimum " , description = " Step for changing value of the argumentin UI " )
2023-08-25 01:58:19 -06:00
choices : Optional [ list [ str ] ] = Field ( default = None , title = " Choices " , description = " Possible values for the argument " )
2023-05-17 13:43:24 -06:00
class ScriptInfo ( BaseModel ) :
name : str = Field ( default = None , title = " Name " , description = " Script name " )
is_alwayson : bool = Field ( default = None , title = " IsAlwayson " , description = " Flag specifying whether this script is an alwayson script " )
is_img2img : bool = Field ( default = None , title = " IsImg2img " , description = " Flag specifying whether this script is an img2img script " )
2023-08-25 01:58:19 -06:00
args : list [ ScriptArg ] = Field ( title = " Arguments " , description = " List of script ' s arguments " )
2023-08-25 08:15:35 -06:00
class ExtensionItem ( BaseModel ) :
name : str = Field ( title = " Name " , description = " Extension name " )
remote : str = Field ( title = " Remote " , description = " Extension Repository URL " )
branch : str = Field ( title = " Branch " , description = " Extension Repository Branch " )
commit_hash : str = Field ( title = " Commit Hash " , description = " Extension Repository Commit Hash " )
version : str = Field ( title = " Version " , description = " Extension Version " )
commit_date : str = Field ( title = " Commit Date " , description = " Extension Repository Commit Date " )
enabled : bool = Field ( title = " Enabled " , description = " Flag specifying whether this extension is enabled " )