Path: blob/master/modules/api/models.py
2447 views
import inspect12from pydantic import BaseModel, Field, create_model3from typing import Any, Optional, Literal4from inflection import underscore5from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img6from modules.shared import sd_upscalers, opts, parser78API_NOT_ALLOWED = [9"self",10"kwargs",11"sd_model",12"outpath_samples",13"outpath_grids",14"sampler_index",15# "do_not_save_samples",16# "do_not_save_grid",17"extra_generation_params",18"overlay_images",19"do_not_reload_embeddings",20"seed_enable_extras",21"prompt_for_display",22"sampler_noise_scheduler_override",23"ddim_discretize"24]2526class ModelDef(BaseModel):27"""Assistance Class for Pydantic Dynamic Model Generation"""2829field: str30field_alias: str31field_type: Any32field_value: Any33field_exclude: bool = False343536class PydanticModelGenerator:37"""38Takes in created classes and stubs them out in a way FastAPI/Pydantic is happy about:39source_data is a snapshot of the default values produced by the class40params are the names of the actual keys required by __init__41"""4243def __init__(44self,45model_name: str = None,46class_instance = None,47additional_fields = None,48):49def field_type_generator(k, v):50field_type = v.annotation5152if field_type == 'Image':53# images are sent as base64 strings via API54field_type = 'str'5556return Optional[field_type]5758def merge_class_params(class_):59all_classes = list(filter(lambda x: x is not object, inspect.getmro(class_)))60parameters = {}61for classes in all_classes:62parameters = {**parameters, **inspect.signature(classes.__init__).parameters}63return parameters6465self._model_name = model_name66self._class_data = merge_class_params(class_instance)6768self._model_def = [69ModelDef(70field=underscore(k),71field_alias=k,72field_type=field_type_generator(k, v),73field_value=None if isinstance(v.default, property) else v.default74)75for (k,v) in self._class_data.items() if k not in API_NOT_ALLOWED76]7778for fields in additional_fields:79self._model_def.append(ModelDef(80field=underscore(fields["key"]),81field_alias=fields["key"],82field_type=fields["type"],83field_value=fields["default"],84field_exclude=fields["exclude"] if "exclude" in fields else False))8586def generate_model(self):87"""88Creates a pydantic BaseModel89from the json and overrides provided at initialization90"""91fields = {92d.field: (d.field_type, Field(default=d.field_value, alias=d.field_alias, exclude=d.field_exclude)) for d in self._model_def93}94DynamicModel = create_model(self._model_name, **fields)95DynamicModel.__config__.allow_population_by_field_name = True96DynamicModel.__config__.allow_mutation = True97return DynamicModel9899StableDiffusionTxt2ImgProcessingAPI = PydanticModelGenerator(100"StableDiffusionProcessingTxt2Img",101StableDiffusionProcessingTxt2Img,102[103{"key": "sampler_index", "type": str, "default": "Euler"},104{"key": "script_name", "type": str, "default": None},105{"key": "script_args", "type": list, "default": []},106{"key": "send_images", "type": bool, "default": True},107{"key": "save_images", "type": bool, "default": False},108{"key": "alwayson_scripts", "type": dict, "default": {}},109{"key": "force_task_id", "type": str, "default": None},110{"key": "infotext", "type": str, "default": None},111]112).generate_model()113114StableDiffusionImg2ImgProcessingAPI = PydanticModelGenerator(115"StableDiffusionProcessingImg2Img",116StableDiffusionProcessingImg2Img,117[118{"key": "sampler_index", "type": str, "default": "Euler"},119{"key": "init_images", "type": list, "default": None},120{"key": "denoising_strength", "type": float, "default": 0.75},121{"key": "mask", "type": str, "default": None},122{"key": "include_init_images", "type": bool, "default": False, "exclude" : True},123{"key": "script_name", "type": str, "default": None},124{"key": "script_args", "type": list, "default": []},125{"key": "send_images", "type": bool, "default": True},126{"key": "save_images", "type": bool, "default": False},127{"key": "alwayson_scripts", "type": dict, "default": {}},128{"key": "force_task_id", "type": str, "default": None},129{"key": "infotext", "type": str, "default": None},130]131).generate_model()132133class TextToImageResponse(BaseModel):134images: list[str] = Field(default=None, title="Image", description="The generated image in base64 format.")135parameters: dict136info: str137138class ImageToImageResponse(BaseModel):139images: list[str] = Field(default=None, title="Image", description="The generated image in base64 format.")140parameters: dict141info: str142143class ExtrasBaseRequest(BaseModel):144resize_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.")145show_extras_results: bool = Field(default=True, title="Show results", description="Should the backend return the generated image?")146gfpgan_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.")147codeformer_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.")148codeformer_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.")149upscaling_resize: float = Field(default=2, title="Upscaling Factor", gt=0, description="By how much to upscale the image, only used when resize_mode=0.")150upscaling_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.")151upscaling_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.")152upscaling_crop: bool = Field(default=True, title="Crop to fit", description="Should the upscaler crop the image to fit in the chosen size?")153upscaler_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])}")154upscaler_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])}")155extras_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.")156upscale_first: bool = Field(default=False, title="Upscale first", description="Should the upscaler run before restoring faces?")157158class ExtraBaseResponse(BaseModel):159html_info: str = Field(title="HTML info", description="A series of HTML tags containing the process info.")160161class ExtrasSingleImageRequest(ExtrasBaseRequest):162image: str = Field(default="", title="Image", description="Image to work on, must be a Base64 string containing the image's data.")163164class ExtrasSingleImageResponse(ExtraBaseResponse):165image: str = Field(default=None, title="Image", description="The generated image in base64 format.")166167class FileData(BaseModel):168data: str = Field(title="File data", description="Base64 representation of the file")169name: str = Field(title="File name")170171class ExtrasBatchImagesRequest(ExtrasBaseRequest):172imageList: list[FileData] = Field(title="Images", description="List of images to work on. Must be Base64 strings")173174class ExtrasBatchImagesResponse(ExtraBaseResponse):175images: list[str] = Field(title="Images", description="The generated images in base64 format.")176177class PNGInfoRequest(BaseModel):178image: str = Field(title="Image", description="The base64 encoded PNG image")179180class PNGInfoResponse(BaseModel):181info: str = Field(title="Image info", description="A string with the parameters used to generate the image")182items: dict = Field(title="Items", description="A dictionary containing all the other fields the image had")183parameters: dict = Field(title="Parameters", description="A dictionary with parsed generation info fields")184185class ProgressRequest(BaseModel):186skip_current_image: bool = Field(default=False, title="Skip current image", description="Skip current image serialization")187188class ProgressResponse(BaseModel):189progress: float = Field(title="Progress", description="The progress with a range of 0 to 1")190eta_relative: float = Field(title="ETA in secs")191state: dict = Field(title="State", description="The current state snapshot")192current_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.")193textinfo: str = Field(default=None, title="Info text", description="Info text used by WebUI.")194195class InterrogateRequest(BaseModel):196image: str = Field(default="", title="Image", description="Image to work on, must be a Base64 string containing the image's data.")197model: str = Field(default="clip", title="Model", description="The interrogate model used.")198199class InterrogateResponse(BaseModel):200caption: str = Field(default=None, title="Caption", description="The generated caption for the image.")201202class TrainResponse(BaseModel):203info: str = Field(title="Train info", description="Response string from train embedding or hypernetwork task.")204205class CreateResponse(BaseModel):206info: str = Field(title="Create info", description="Response string from create embedding or hypernetwork task.")207208fields = {}209for key, metadata in opts.data_labels.items():210value = opts.data.get(key)211optType = opts.typemap.get(type(metadata.default), type(metadata.default)) if metadata.default else Any212213if metadata is not None:214fields.update({key: (Optional[optType], Field(default=metadata.default, description=metadata.label))})215else:216fields.update({key: (Optional[optType], Field())})217218OptionsModel = create_model("Options", **fields)219220flags = {}221_options = vars(parser)['_option_string_actions']222for key in _options:223if(_options[key].dest != 'help'):224flag = _options[key]225_type = str226if _options[key].default is not None:227_type = type(_options[key].default)228flags.update({flag.dest: (_type, Field(default=flag.default, description=flag.help))})229230FlagsModel = create_model("Flags", **flags)231232class SamplerItem(BaseModel):233name: str = Field(title="Name")234aliases: list[str] = Field(title="Aliases")235options: dict[str, str] = Field(title="Options")236237class SchedulerItem(BaseModel):238name: str = Field(title="Name")239label: str = Field(title="Label")240aliases: Optional[list[str]] = Field(title="Aliases")241default_rho: Optional[float] = Field(title="Default Rho")242need_inner_model: Optional[bool] = Field(title="Needs Inner Model")243244class UpscalerItem(BaseModel):245name: str = Field(title="Name")246model_name: Optional[str] = Field(title="Model Name")247model_path: Optional[str] = Field(title="Path")248model_url: Optional[str] = Field(title="URL")249scale: Optional[float] = Field(title="Scale")250251class LatentUpscalerModeItem(BaseModel):252name: str = Field(title="Name")253254class SDModelItem(BaseModel):255title: str = Field(title="Title")256model_name: str = Field(title="Model Name")257hash: Optional[str] = Field(title="Short hash")258sha256: Optional[str] = Field(title="sha256 hash")259filename: str = Field(title="Filename")260config: Optional[str] = Field(title="Config file")261262class SDVaeItem(BaseModel):263model_name: str = Field(title="Model Name")264filename: str = Field(title="Filename")265266class HypernetworkItem(BaseModel):267name: str = Field(title="Name")268path: Optional[str] = Field(title="Path")269270class FaceRestorerItem(BaseModel):271name: str = Field(title="Name")272cmd_dir: Optional[str] = Field(title="Path")273274class RealesrganItem(BaseModel):275name: str = Field(title="Name")276path: Optional[str] = Field(title="Path")277scale: Optional[int] = Field(title="Scale")278279class PromptStyleItem(BaseModel):280name: str = Field(title="Name")281prompt: Optional[str] = Field(title="Prompt")282negative_prompt: Optional[str] = Field(title="Negative Prompt")283284285class EmbeddingItem(BaseModel):286step: Optional[int] = Field(title="Step", description="The number of steps that were used to train this embedding, if available")287sd_checkpoint: Optional[str] = Field(title="SD Checkpoint", description="The hash of the checkpoint this embedding was trained on, if available")288sd_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")289shape: int = Field(title="Shape", description="The length of each individual vector in the embedding")290vectors: int = Field(title="Vectors", description="The number of vectors in the embedding")291292class EmbeddingsResponse(BaseModel):293loaded: dict[str, EmbeddingItem] = Field(title="Loaded", description="Embeddings loaded for the current model")294skipped: dict[str, EmbeddingItem] = Field(title="Skipped", description="Embeddings skipped for the current model (likely due to architecture incompatibility)")295296class MemoryResponse(BaseModel):297ram: dict = Field(title="RAM", description="System memory stats")298cuda: dict = Field(title="CUDA", description="nVidia CUDA memory stats")299300301class ScriptsList(BaseModel):302txt2img: list = Field(default=None, title="Txt2img", description="Titles of scripts (txt2img)")303img2img: list = Field(default=None, title="Img2img", description="Titles of scripts (img2img)")304305306class ScriptArg(BaseModel):307label: str = Field(default=None, title="Label", description="Name of the argument in UI")308value: Optional[Any] = Field(default=None, title="Value", description="Default value of the argument")309minimum: Optional[Any] = Field(default=None, title="Minimum", description="Minimum allowed value for the argumentin UI")310maximum: Optional[Any] = Field(default=None, title="Minimum", description="Maximum allowed value for the argumentin UI")311step: Optional[Any] = Field(default=None, title="Minimum", description="Step for changing value of the argumentin UI")312choices: Optional[list[str]] = Field(default=None, title="Choices", description="Possible values for the argument")313314315class ScriptInfo(BaseModel):316name: str = Field(default=None, title="Name", description="Script name")317is_alwayson: bool = Field(default=None, title="IsAlwayson", description="Flag specifying whether this script is an alwayson script")318is_img2img: bool = Field(default=None, title="IsImg2img", description="Flag specifying whether this script is an img2img script")319args: list[ScriptArg] = Field(title="Arguments", description="List of script's arguments")320321class ExtensionItem(BaseModel):322name: str = Field(title="Name", description="Extension name")323remote: str = Field(title="Remote", description="Extension Repository URL")324branch: str = Field(title="Branch", description="Extension Repository Branch")325commit_hash: str = Field(title="Commit Hash", description="Extension Repository Commit Hash")326version: str = Field(title="Version", description="Extension Version")327commit_date: str = Field(title="Commit Date", description="Extension Repository Commit Date")328enabled: bool = Field(title="Enabled", description="Flag specifying whether this extension is enabled")329330331