models.py 17 KB

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