Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
AUTOMATIC1111
GitHub Repository: AUTOMATIC1111/stable-diffusion-webui
Path: blob/master/modules/api/models.py
2447 views
1
import inspect
2
3
from pydantic import BaseModel, Field, create_model
4
from typing import Any, Optional, Literal
5
from inflection import underscore
6
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img
7
from modules.shared import sd_upscalers, opts, parser
8
9
API_NOT_ALLOWED = [
10
"self",
11
"kwargs",
12
"sd_model",
13
"outpath_samples",
14
"outpath_grids",
15
"sampler_index",
16
# "do_not_save_samples",
17
# "do_not_save_grid",
18
"extra_generation_params",
19
"overlay_images",
20
"do_not_reload_embeddings",
21
"seed_enable_extras",
22
"prompt_for_display",
23
"sampler_noise_scheduler_override",
24
"ddim_discretize"
25
]
26
27
class ModelDef(BaseModel):
28
"""Assistance Class for Pydantic Dynamic Model Generation"""
29
30
field: str
31
field_alias: str
32
field_type: Any
33
field_value: Any
34
field_exclude: bool = False
35
36
37
class PydanticModelGenerator:
38
"""
39
Takes in created classes and stubs them out in a way FastAPI/Pydantic is happy about:
40
source_data is a snapshot of the default values produced by the class
41
params are the names of the actual keys required by __init__
42
"""
43
44
def __init__(
45
self,
46
model_name: str = None,
47
class_instance = None,
48
additional_fields = None,
49
):
50
def field_type_generator(k, v):
51
field_type = v.annotation
52
53
if field_type == 'Image':
54
# images are sent as base64 strings via API
55
field_type = 'str'
56
57
return Optional[field_type]
58
59
def merge_class_params(class_):
60
all_classes = list(filter(lambda x: x is not object, inspect.getmro(class_)))
61
parameters = {}
62
for classes in all_classes:
63
parameters = {**parameters, **inspect.signature(classes.__init__).parameters}
64
return parameters
65
66
self._model_name = model_name
67
self._class_data = merge_class_params(class_instance)
68
69
self._model_def = [
70
ModelDef(
71
field=underscore(k),
72
field_alias=k,
73
field_type=field_type_generator(k, v),
74
field_value=None if isinstance(v.default, property) else v.default
75
)
76
for (k,v) in self._class_data.items() if k not in API_NOT_ALLOWED
77
]
78
79
for fields in additional_fields:
80
self._model_def.append(ModelDef(
81
field=underscore(fields["key"]),
82
field_alias=fields["key"],
83
field_type=fields["type"],
84
field_value=fields["default"],
85
field_exclude=fields["exclude"] if "exclude" in fields else False))
86
87
def generate_model(self):
88
"""
89
Creates a pydantic BaseModel
90
from the json and overrides provided at initialization
91
"""
92
fields = {
93
d.field: (d.field_type, Field(default=d.field_value, alias=d.field_alias, exclude=d.field_exclude)) for d in self._model_def
94
}
95
DynamicModel = create_model(self._model_name, **fields)
96
DynamicModel.__config__.allow_population_by_field_name = True
97
DynamicModel.__config__.allow_mutation = True
98
return DynamicModel
99
100
StableDiffusionTxt2ImgProcessingAPI = PydanticModelGenerator(
101
"StableDiffusionProcessingTxt2Img",
102
StableDiffusionProcessingTxt2Img,
103
[
104
{"key": "sampler_index", "type": str, "default": "Euler"},
105
{"key": "script_name", "type": str, "default": None},
106
{"key": "script_args", "type": list, "default": []},
107
{"key": "send_images", "type": bool, "default": True},
108
{"key": "save_images", "type": bool, "default": False},
109
{"key": "alwayson_scripts", "type": dict, "default": {}},
110
{"key": "force_task_id", "type": str, "default": None},
111
{"key": "infotext", "type": str, "default": None},
112
]
113
).generate_model()
114
115
StableDiffusionImg2ImgProcessingAPI = PydanticModelGenerator(
116
"StableDiffusionProcessingImg2Img",
117
StableDiffusionProcessingImg2Img,
118
[
119
{"key": "sampler_index", "type": str, "default": "Euler"},
120
{"key": "init_images", "type": list, "default": None},
121
{"key": "denoising_strength", "type": float, "default": 0.75},
122
{"key": "mask", "type": str, "default": None},
123
{"key": "include_init_images", "type": bool, "default": False, "exclude" : True},
124
{"key": "script_name", "type": str, "default": None},
125
{"key": "script_args", "type": list, "default": []},
126
{"key": "send_images", "type": bool, "default": True},
127
{"key": "save_images", "type": bool, "default": False},
128
{"key": "alwayson_scripts", "type": dict, "default": {}},
129
{"key": "force_task_id", "type": str, "default": None},
130
{"key": "infotext", "type": str, "default": None},
131
]
132
).generate_model()
133
134
class TextToImageResponse(BaseModel):
135
images: list[str] = Field(default=None, title="Image", description="The generated image in base64 format.")
136
parameters: dict
137
info: str
138
139
class ImageToImageResponse(BaseModel):
140
images: list[str] = Field(default=None, title="Image", description="The generated image in base64 format.")
141
parameters: dict
142
info: str
143
144
class ExtrasBaseRequest(BaseModel):
145
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.")
146
show_extras_results: bool = Field(default=True, title="Show results", description="Should the backend return the generated image?")
147
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.")
148
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.")
149
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.")
150
upscaling_resize: float = Field(default=2, title="Upscaling Factor", gt=0, description="By how much to upscale the image, only used when resize_mode=0.")
151
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.")
152
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.")
153
upscaling_crop: bool = Field(default=True, title="Crop to fit", description="Should the upscaler crop the image to fit in the chosen size?")
154
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])}")
155
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])}")
156
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.")
157
upscale_first: bool = Field(default=False, title="Upscale first", description="Should the upscaler run before restoring faces?")
158
159
class ExtraBaseResponse(BaseModel):
160
html_info: str = Field(title="HTML info", description="A series of HTML tags containing the process info.")
161
162
class ExtrasSingleImageRequest(ExtrasBaseRequest):
163
image: str = Field(default="", title="Image", description="Image to work on, must be a Base64 string containing the image's data.")
164
165
class ExtrasSingleImageResponse(ExtraBaseResponse):
166
image: str = Field(default=None, title="Image", description="The generated image in base64 format.")
167
168
class FileData(BaseModel):
169
data: str = Field(title="File data", description="Base64 representation of the file")
170
name: str = Field(title="File name")
171
172
class ExtrasBatchImagesRequest(ExtrasBaseRequest):
173
imageList: list[FileData] = Field(title="Images", description="List of images to work on. Must be Base64 strings")
174
175
class ExtrasBatchImagesResponse(ExtraBaseResponse):
176
images: list[str] = Field(title="Images", description="The generated images in base64 format.")
177
178
class PNGInfoRequest(BaseModel):
179
image: str = Field(title="Image", description="The base64 encoded PNG image")
180
181
class PNGInfoResponse(BaseModel):
182
info: str = Field(title="Image info", description="A string with the parameters used to generate the image")
183
items: dict = Field(title="Items", description="A dictionary containing all the other fields the image had")
184
parameters: dict = Field(title="Parameters", description="A dictionary with parsed generation info fields")
185
186
class ProgressRequest(BaseModel):
187
skip_current_image: bool = Field(default=False, title="Skip current image", description="Skip current image serialization")
188
189
class ProgressResponse(BaseModel):
190
progress: float = Field(title="Progress", description="The progress with a range of 0 to 1")
191
eta_relative: float = Field(title="ETA in secs")
192
state: dict = Field(title="State", description="The current state snapshot")
193
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.")
194
textinfo: str = Field(default=None, title="Info text", description="Info text used by WebUI.")
195
196
class InterrogateRequest(BaseModel):
197
image: str = Field(default="", title="Image", description="Image to work on, must be a Base64 string containing the image's data.")
198
model: str = Field(default="clip", title="Model", description="The interrogate model used.")
199
200
class InterrogateResponse(BaseModel):
201
caption: str = Field(default=None, title="Caption", description="The generated caption for the image.")
202
203
class TrainResponse(BaseModel):
204
info: str = Field(title="Train info", description="Response string from train embedding or hypernetwork task.")
205
206
class CreateResponse(BaseModel):
207
info: str = Field(title="Create info", description="Response string from create embedding or hypernetwork task.")
208
209
fields = {}
210
for key, metadata in opts.data_labels.items():
211
value = opts.data.get(key)
212
optType = opts.typemap.get(type(metadata.default), type(metadata.default)) if metadata.default else Any
213
214
if metadata is not None:
215
fields.update({key: (Optional[optType], Field(default=metadata.default, description=metadata.label))})
216
else:
217
fields.update({key: (Optional[optType], Field())})
218
219
OptionsModel = create_model("Options", **fields)
220
221
flags = {}
222
_options = vars(parser)['_option_string_actions']
223
for key in _options:
224
if(_options[key].dest != 'help'):
225
flag = _options[key]
226
_type = str
227
if _options[key].default is not None:
228
_type = type(_options[key].default)
229
flags.update({flag.dest: (_type, Field(default=flag.default, description=flag.help))})
230
231
FlagsModel = create_model("Flags", **flags)
232
233
class SamplerItem(BaseModel):
234
name: str = Field(title="Name")
235
aliases: list[str] = Field(title="Aliases")
236
options: dict[str, str] = Field(title="Options")
237
238
class SchedulerItem(BaseModel):
239
name: str = Field(title="Name")
240
label: str = Field(title="Label")
241
aliases: Optional[list[str]] = Field(title="Aliases")
242
default_rho: Optional[float] = Field(title="Default Rho")
243
need_inner_model: Optional[bool] = Field(title="Needs Inner Model")
244
245
class UpscalerItem(BaseModel):
246
name: str = Field(title="Name")
247
model_name: Optional[str] = Field(title="Model Name")
248
model_path: Optional[str] = Field(title="Path")
249
model_url: Optional[str] = Field(title="URL")
250
scale: Optional[float] = Field(title="Scale")
251
252
class LatentUpscalerModeItem(BaseModel):
253
name: str = Field(title="Name")
254
255
class SDModelItem(BaseModel):
256
title: str = Field(title="Title")
257
model_name: str = Field(title="Model Name")
258
hash: Optional[str] = Field(title="Short hash")
259
sha256: Optional[str] = Field(title="sha256 hash")
260
filename: str = Field(title="Filename")
261
config: Optional[str] = Field(title="Config file")
262
263
class SDVaeItem(BaseModel):
264
model_name: str = Field(title="Model Name")
265
filename: str = Field(title="Filename")
266
267
class HypernetworkItem(BaseModel):
268
name: str = Field(title="Name")
269
path: Optional[str] = Field(title="Path")
270
271
class FaceRestorerItem(BaseModel):
272
name: str = Field(title="Name")
273
cmd_dir: Optional[str] = Field(title="Path")
274
275
class RealesrganItem(BaseModel):
276
name: str = Field(title="Name")
277
path: Optional[str] = Field(title="Path")
278
scale: Optional[int] = Field(title="Scale")
279
280
class PromptStyleItem(BaseModel):
281
name: str = Field(title="Name")
282
prompt: Optional[str] = Field(title="Prompt")
283
negative_prompt: Optional[str] = Field(title="Negative Prompt")
284
285
286
class EmbeddingItem(BaseModel):
287
step: Optional[int] = Field(title="Step", description="The number of steps that were used to train this embedding, if available")
288
sd_checkpoint: Optional[str] = Field(title="SD Checkpoint", description="The hash of the checkpoint this embedding was trained on, if available")
289
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")
290
shape: int = Field(title="Shape", description="The length of each individual vector in the embedding")
291
vectors: int = Field(title="Vectors", description="The number of vectors in the embedding")
292
293
class EmbeddingsResponse(BaseModel):
294
loaded: dict[str, EmbeddingItem] = Field(title="Loaded", description="Embeddings loaded for the current model")
295
skipped: dict[str, EmbeddingItem] = Field(title="Skipped", description="Embeddings skipped for the current model (likely due to architecture incompatibility)")
296
297
class MemoryResponse(BaseModel):
298
ram: dict = Field(title="RAM", description="System memory stats")
299
cuda: dict = Field(title="CUDA", description="nVidia CUDA memory stats")
300
301
302
class ScriptsList(BaseModel):
303
txt2img: list = Field(default=None, title="Txt2img", description="Titles of scripts (txt2img)")
304
img2img: list = Field(default=None, title="Img2img", description="Titles of scripts (img2img)")
305
306
307
class ScriptArg(BaseModel):
308
label: str = Field(default=None, title="Label", description="Name of the argument in UI")
309
value: Optional[Any] = Field(default=None, title="Value", description="Default value of the argument")
310
minimum: Optional[Any] = Field(default=None, title="Minimum", description="Minimum allowed value for the argumentin UI")
311
maximum: Optional[Any] = Field(default=None, title="Minimum", description="Maximum allowed value for the argumentin UI")
312
step: Optional[Any] = Field(default=None, title="Minimum", description="Step for changing value of the argumentin UI")
313
choices: Optional[list[str]] = Field(default=None, title="Choices", description="Possible values for the argument")
314
315
316
class ScriptInfo(BaseModel):
317
name: str = Field(default=None, title="Name", description="Script name")
318
is_alwayson: bool = Field(default=None, title="IsAlwayson", description="Flag specifying whether this script is an alwayson script")
319
is_img2img: bool = Field(default=None, title="IsImg2img", description="Flag specifying whether this script is an img2img script")
320
args: list[ScriptArg] = Field(title="Arguments", description="List of script's arguments")
321
322
class ExtensionItem(BaseModel):
323
name: str = Field(title="Name", description="Extension name")
324
remote: str = Field(title="Remote", description="Extension Repository URL")
325
branch: str = Field(title="Branch", description="Extension Repository Branch")
326
commit_hash: str = Field(title="Commit Hash", description="Extension Repository Commit Hash")
327
version: str = Field(title="Version", description="Extension Version")
328
commit_date: str = Field(title="Commit Date", description="Extension Repository Commit Date")
329
enabled: bool = Field(title="Enabled", description="Flag specifying whether this extension is enabled")
330
331