daswer123 commited on
Commit
c365f92
1 Parent(s): 0d50185

Upload 23 files

Browse files
api/api.py ADDED
@@ -0,0 +1,996 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import io
3
+ import os
4
+ import time
5
+ import itertools
6
+ import datetime
7
+ import uvicorn
8
+ import ipaddress
9
+ import requests
10
+ import gradio as gr
11
+ import numpy as np
12
+ from threading import Lock
13
+ from io import BytesIO
14
+ from fastapi import APIRouter, Depends, FastAPI, Request, Response
15
+ from fastapi.security import HTTPBasic, HTTPBasicCredentials
16
+ from fastapi.exceptions import HTTPException
17
+ from fastapi.responses import JSONResponse
18
+ from fastapi.encoders import jsonable_encoder
19
+ from secrets import compare_digest
20
+
21
+ import modules.shared as shared
22
+ from modules import sd_samplers, deepbooru, sd_hijack, images, scripts, ui, postprocessing, errors, restart, shared_items, script_callbacks, infotext_utils, sd_models
23
+ from modules.api import models
24
+ from modules.shared import opts
25
+ from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images
26
+ from modules.textual_inversion.textual_inversion import create_embedding, train_embedding
27
+ from modules.hypernetworks.hypernetwork import create_hypernetwork, train_hypernetwork
28
+ from PIL import PngImagePlugin, Image
29
+ from modules.sd_models_config import find_checkpoint_config_near_filename
30
+ from modules.realesrgan_model import get_realesrgan_models
31
+ from modules import devices
32
+ from typing import Any
33
+ import piexif
34
+ import piexif.helper
35
+ from contextlib import closing
36
+ from modules.progress import create_task_id, add_task_to_queue, start_task, finish_task, current_task
37
+
38
+ def script_name_to_index(name, scripts):
39
+ try:
40
+ return [script.title().lower() for script in scripts].index(name.lower())
41
+ except Exception as e:
42
+ raise HTTPException(status_code=422, detail=f"Script '{name}' not found") from e
43
+
44
+
45
+ def validate_sampler_name(name):
46
+ config = sd_samplers.all_samplers_map.get(name, None)
47
+ if config is None:
48
+ raise HTTPException(status_code=404, detail="Sampler not found")
49
+
50
+ return name
51
+
52
+
53
+ def setUpscalers(req: dict):
54
+ reqDict = vars(req)
55
+ reqDict['extras_upscaler_1'] = reqDict.pop('upscaler_1', None)
56
+ reqDict['extras_upscaler_2'] = reqDict.pop('upscaler_2', None)
57
+ return reqDict
58
+
59
+
60
+ def verify_url(url):
61
+ """Returns True if the url refers to a global resource."""
62
+
63
+ import socket
64
+ from urllib.parse import urlparse
65
+ try:
66
+ parsed_url = urlparse(url)
67
+ domain_name = parsed_url.netloc
68
+ host = socket.gethostbyname_ex(domain_name)
69
+ for ip in host[2]:
70
+ ip_addr = ipaddress.ip_address(ip)
71
+ if not ip_addr.is_global:
72
+ return False
73
+ except Exception:
74
+ return False
75
+
76
+ return True
77
+
78
+
79
+ def decode_base64_to_image(encoding):
80
+ if encoding.startswith("http://") or encoding.startswith("https://"):
81
+ if not opts.api_enable_requests:
82
+ raise HTTPException(status_code=500, detail="Requests not allowed")
83
+
84
+ if opts.api_forbid_local_requests and not verify_url(encoding):
85
+ raise HTTPException(status_code=500, detail="Request to local resource not allowed")
86
+
87
+ headers = {'user-agent': opts.api_useragent} if opts.api_useragent else {}
88
+ response = requests.get(encoding, timeout=30, headers=headers)
89
+ try:
90
+ image = Image.open(BytesIO(response.content))
91
+ return image
92
+ except Exception as e:
93
+ raise HTTPException(status_code=500, detail="Invalid image url") from e
94
+
95
+ if encoding.startswith("data:image/"):
96
+ encoding = encoding.split(";")[1].split(",")[1]
97
+ try:
98
+ image = Image.open(BytesIO(base64.b64decode(encoding)))
99
+ return image
100
+ except Exception as e:
101
+ raise HTTPException(status_code=500, detail="Invalid encoded image") from e
102
+
103
+
104
+ def encode_pil_to_base64(image):
105
+ with io.BytesIO() as output_bytes:
106
+ if isinstance(image, str):
107
+ return image
108
+ if isinstance(image, np.ndarray):
109
+ image = Image.fromarray(image)
110
+ if opts.samples_format.lower() == 'png':
111
+ use_metadata = False
112
+ metadata = PngImagePlugin.PngInfo()
113
+ for key, value in image.info.items():
114
+ if isinstance(key, str) and isinstance(value, str):
115
+ metadata.add_text(key, value)
116
+ use_metadata = True
117
+ image.save(output_bytes, format="PNG", pnginfo=(metadata if use_metadata else None), quality=opts.jpeg_quality)
118
+
119
+ elif opts.samples_format.lower() in ("jpg", "jpeg", "webp"):
120
+ if image.mode == "RGBA":
121
+ image = image.convert("RGB")
122
+ parameters = image.info.get('parameters', None)
123
+ exif_bytes = piexif.dump({
124
+ "Exif": { piexif.ExifIFD.UserComment: piexif.helper.UserComment.dump(parameters or "", encoding="unicode") }
125
+ })
126
+ if opts.samples_format.lower() in ("jpg", "jpeg"):
127
+ image.save(output_bytes, format="JPEG", exif = exif_bytes, quality=opts.jpeg_quality)
128
+ else:
129
+ image.save(output_bytes, format="WEBP", exif = exif_bytes, quality=opts.jpeg_quality)
130
+
131
+ else:
132
+ raise HTTPException(status_code=500, detail="Invalid image format")
133
+
134
+ bytes_data = output_bytes.getvalue()
135
+
136
+ return base64.b64encode(bytes_data)
137
+
138
+
139
+ def api_middleware(app: FastAPI):
140
+ rich_available = False
141
+ try:
142
+ if os.environ.get('WEBUI_RICH_EXCEPTIONS', None) is not None:
143
+ import anyio # importing just so it can be placed on silent list
144
+ import starlette # importing just so it can be placed on silent list
145
+ from rich.console import Console
146
+ console = Console()
147
+ rich_available = True
148
+ except Exception:
149
+ pass
150
+
151
+ @app.middleware("http")
152
+ async def log_and_time(req: Request, call_next):
153
+ ts = time.time()
154
+ res: Response = await call_next(req)
155
+ duration = str(round(time.time() - ts, 4))
156
+ res.headers["X-Process-Time"] = duration
157
+ endpoint = req.scope.get('path', 'err')
158
+ if shared.cmd_opts.api_log and endpoint.startswith('/sdapi'):
159
+ print('API {t} {code} {prot}/{ver} {method} {endpoint} {cli} {duration}'.format(
160
+ t=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"),
161
+ code=res.status_code,
162
+ ver=req.scope.get('http_version', '0.0'),
163
+ cli=req.scope.get('client', ('0:0.0.0', 0))[0],
164
+ prot=req.scope.get('scheme', 'err'),
165
+ method=req.scope.get('method', 'err'),
166
+ endpoint=endpoint,
167
+ duration=duration,
168
+ ))
169
+ return res
170
+
171
+ def handle_exception(request: Request, e: Exception):
172
+ err = {
173
+ "error": type(e).__name__,
174
+ "detail": vars(e).get('detail', ''),
175
+ "body": vars(e).get('body', ''),
176
+ "errors": str(e),
177
+ }
178
+ if not isinstance(e, HTTPException): # do not print backtrace on known httpexceptions
179
+ message = f"API error: {request.method}: {request.url} {err}"
180
+ if rich_available:
181
+ print(message)
182
+ console.print_exception(show_locals=True, max_frames=2, extra_lines=1, suppress=[anyio, starlette], word_wrap=False, width=min([console.width, 200]))
183
+ else:
184
+ errors.report(message, exc_info=True)
185
+ return JSONResponse(status_code=vars(e).get('status_code', 500), content=jsonable_encoder(err))
186
+
187
+ @app.middleware("http")
188
+ async def exception_handling(request: Request, call_next):
189
+ try:
190
+ return await call_next(request)
191
+ except Exception as e:
192
+ return handle_exception(request, e)
193
+
194
+ @app.exception_handler(Exception)
195
+ async def fastapi_exception_handler(request: Request, e: Exception):
196
+ return handle_exception(request, e)
197
+
198
+ @app.exception_handler(HTTPException)
199
+ async def http_exception_handler(request: Request, e: HTTPException):
200
+ return handle_exception(request, e)
201
+
202
+
203
+ class Api:
204
+ def __init__(self, app: FastAPI, queue_lock: Lock):
205
+ if shared.cmd_opts.api_auth:
206
+ self.credentials = {}
207
+ for auth in shared.cmd_opts.api_auth.split(","):
208
+ user, password = auth.split(":")
209
+ self.credentials[user] = password
210
+
211
+ self.router = APIRouter()
212
+ self.app = app
213
+ self.queue_lock = queue_lock
214
+ api_middleware(self.app)
215
+ self.add_api_route("/sdapi/v1/txt2img", self.text2imgapi, methods=["POST"], response_model=models.TextToImageResponse)
216
+ self.add_api_route("/sdapi/v1/txt2imgmod", self.text2imgapimod, methods=["POST"], response_model=models.TextToImageResponseMod)
217
+ self.add_api_route("/sdapi/v1/img2img", self.img2imgapi, methods=["POST"], response_model=models.ImageToImageResponse)
218
+ self.add_api_route("/sdapi/v1/extra-single-image", self.extras_single_image_api, methods=["POST"], response_model=models.ExtrasSingleImageResponse)
219
+ self.add_api_route("/sdapi/v1/extra-batch-images", self.extras_batch_images_api, methods=["POST"], response_model=models.ExtrasBatchImagesResponse)
220
+ self.add_api_route("/sdapi/v1/png-info", self.pnginfoapi, methods=["POST"], response_model=models.PNGInfoResponse)
221
+ self.add_api_route("/sdapi/v1/progress", self.progressapi, methods=["GET"], response_model=models.ProgressResponse)
222
+ self.add_api_route("/sdapi/v1/interrogate", self.interrogateapi, methods=["POST"])
223
+ self.add_api_route("/sdapi/v1/interrupt", self.interruptapi, methods=["POST"])
224
+ self.add_api_route("/sdapi/v1/skip", self.skip, methods=["POST"])
225
+ self.add_api_route("/sdapi/v1/options", self.get_config, methods=["GET"], response_model=models.OptionsModel)
226
+ self.add_api_route("/sdapi/v1/options", self.set_config, methods=["POST"])
227
+ self.add_api_route("/sdapi/v1/cmd-flags", self.get_cmd_flags, methods=["GET"], response_model=models.FlagsModel)
228
+ self.add_api_route("/sdapi/v1/samplers", self.get_samplers, methods=["GET"], response_model=list[models.SamplerItem])
229
+ self.add_api_route("/sdapi/v1/upscalers", self.get_upscalers, methods=["GET"], response_model=list[models.UpscalerItem])
230
+ self.add_api_route("/sdapi/v1/latent-upscale-modes", self.get_latent_upscale_modes, methods=["GET"], response_model=list[models.LatentUpscalerModeItem])
231
+ self.add_api_route("/sdapi/v1/sd-models", self.get_sd_models, methods=["GET"], response_model=list[models.SDModelItem])
232
+ self.add_api_route("/sdapi/v1/sd-vae", self.get_sd_vaes, methods=["GET"], response_model=list[models.SDVaeItem])
233
+ self.add_api_route("/sdapi/v1/hypernetworks", self.get_hypernetworks, methods=["GET"], response_model=list[models.HypernetworkItem])
234
+ self.add_api_route("/sdapi/v1/face-restorers", self.get_face_restorers, methods=["GET"], response_model=list[models.FaceRestorerItem])
235
+ self.add_api_route("/sdapi/v1/realesrgan-models", self.get_realesrgan_models, methods=["GET"], response_model=list[models.RealesrganItem])
236
+ self.add_api_route("/sdapi/v1/prompt-styles", self.get_prompt_styles, methods=["GET"], response_model=list[models.PromptStyleItem])
237
+ self.add_api_route("/sdapi/v1/embeddings", self.get_embeddings, methods=["GET"], response_model=models.EmbeddingsResponse)
238
+ self.add_api_route("/sdapi/v1/refresh-embeddings", self.refresh_embeddings, methods=["POST"])
239
+ self.add_api_route("/sdapi/v1/refresh-checkpoints", self.refresh_checkpoints, methods=["POST"])
240
+ self.add_api_route("/sdapi/v1/refresh-vae", self.refresh_vae, methods=["POST"])
241
+ self.add_api_route("/sdapi/v1/create/embedding", self.create_embedding, methods=["POST"], response_model=models.CreateResponse)
242
+ self.add_api_route("/sdapi/v1/create/hypernetwork", self.create_hypernetwork, methods=["POST"], response_model=models.CreateResponse)
243
+ self.add_api_route("/sdapi/v1/train/embedding", self.train_embedding, methods=["POST"], response_model=models.TrainResponse)
244
+ self.add_api_route("/sdapi/v1/train/hypernetwork", self.train_hypernetwork, methods=["POST"], response_model=models.TrainResponse)
245
+ self.add_api_route("/sdapi/v1/memory", self.get_memory, methods=["GET"], response_model=models.MemoryResponse)
246
+ self.add_api_route("/sdapi/v1/unload-checkpoint", self.unloadapi, methods=["POST"])
247
+ self.add_api_route("/sdapi/v1/reload-checkpoint", self.reloadapi, methods=["POST"])
248
+ self.add_api_route("/sdapi/v1/scripts", self.get_scripts_list, methods=["GET"], response_model=models.ScriptsList)
249
+ self.add_api_route("/sdapi/v1/script-info", self.get_script_info, methods=["GET"], response_model=list[models.ScriptInfo])
250
+ self.add_api_route("/sdapi/v1/extensions", self.get_extensions_list, methods=["GET"], response_model=list[models.ExtensionItem])
251
+
252
+ if shared.cmd_opts.api_server_stop:
253
+ self.add_api_route("/sdapi/v1/server-kill", self.kill_webui, methods=["POST"])
254
+ self.add_api_route("/sdapi/v1/server-restart", self.restart_webui, methods=["POST"])
255
+ self.add_api_route("/sdapi/v1/server-stop", self.stop_webui, methods=["POST"])
256
+
257
+ self.default_script_arg_txt2img = []
258
+ self.default_script_arg_img2img = []
259
+
260
+ txt2img_script_runner = scripts.scripts_txt2img
261
+ img2img_script_runner = scripts.scripts_img2img
262
+
263
+ if not txt2img_script_runner.scripts or not img2img_script_runner.scripts:
264
+ ui.create_ui()
265
+
266
+ if not txt2img_script_runner.scripts:
267
+ txt2img_script_runner.initialize_scripts(False)
268
+ if not self.default_script_arg_txt2img:
269
+ self.default_script_arg_txt2img = self.init_default_script_args(txt2img_script_runner)
270
+
271
+ if not img2img_script_runner.scripts:
272
+ img2img_script_runner.initialize_scripts(True)
273
+ if not self.default_script_arg_img2img:
274
+ self.default_script_arg_img2img = self.init_default_script_args(img2img_script_runner)
275
+
276
+
277
+
278
+ def add_api_route(self, path: str, endpoint, **kwargs):
279
+ if shared.cmd_opts.api_auth:
280
+ return self.app.add_api_route(path, endpoint, dependencies=[Depends(self.auth)], **kwargs)
281
+ return self.app.add_api_route(path, endpoint, **kwargs)
282
+
283
+ def auth(self, credentials: HTTPBasicCredentials = Depends(HTTPBasic())):
284
+ if credentials.username in self.credentials:
285
+ if compare_digest(credentials.password, self.credentials[credentials.username]):
286
+ return True
287
+
288
+ raise HTTPException(status_code=401, detail="Incorrect username or password", headers={"WWW-Authenticate": "Basic"})
289
+
290
+ def get_selectable_script(self, script_name, script_runner):
291
+ if script_name is None or script_name == "":
292
+ return None, None
293
+
294
+ script_idx = script_name_to_index(script_name, script_runner.selectable_scripts)
295
+ script = script_runner.selectable_scripts[script_idx]
296
+ return script, script_idx
297
+
298
+ def get_scripts_list(self):
299
+ t2ilist = [script.name for script in scripts.scripts_txt2img.scripts if script.name is not None]
300
+ i2ilist = [script.name for script in scripts.scripts_img2img.scripts if script.name is not None]
301
+
302
+ return models.ScriptsList(txt2img=t2ilist, img2img=i2ilist)
303
+
304
+ def get_script_info(self):
305
+ res = []
306
+
307
+ for script_list in [scripts.scripts_txt2img.scripts, scripts.scripts_img2img.scripts]:
308
+ res += [script.api_info for script in script_list if script.api_info is not None]
309
+
310
+ return res
311
+
312
+ def get_script(self, script_name, script_runner):
313
+ if script_name is None or script_name == "":
314
+ return None, None
315
+
316
+ script_idx = script_name_to_index(script_name, script_runner.scripts)
317
+ return script_runner.scripts[script_idx]
318
+
319
+ def init_default_script_args(self, script_runner):
320
+ #find max idx from the scripts in runner and generate a none array to init script_args
321
+ last_arg_index = 1
322
+ for script in script_runner.scripts:
323
+ if last_arg_index < script.args_to:
324
+ last_arg_index = script.args_to
325
+ # None everywhere except position 0 to initialize script args
326
+ script_args = [None]*last_arg_index
327
+ script_args[0] = 0
328
+
329
+ # get default values
330
+ with gr.Blocks(): # will throw errors calling ui function without this
331
+ for script in script_runner.scripts:
332
+ if script.ui(script.is_img2img):
333
+ ui_default_values = []
334
+ for elem in script.ui(script.is_img2img):
335
+ ui_default_values.append(elem.value)
336
+ script_args[script.args_from:script.args_to] = ui_default_values
337
+ return script_args
338
+
339
+ def init_script_args(self, request, default_script_args, selectable_scripts, selectable_idx, script_runner, *, input_script_args=None):
340
+ script_args = default_script_args.copy()
341
+
342
+ if input_script_args is not None:
343
+ for index, value in input_script_args.items():
344
+ script_args[index] = value
345
+
346
+ # position 0 in script_arg is the idx+1 of the selectable script that is going to be run when using scripts.scripts_*2img.run()
347
+ if selectable_scripts:
348
+ script_args[selectable_scripts.args_from:selectable_scripts.args_to] = request.script_args
349
+ script_args[0] = selectable_idx + 1
350
+
351
+ # Now check for always on scripts
352
+ if request.alwayson_scripts:
353
+ for alwayson_script_name in request.alwayson_scripts.keys():
354
+ alwayson_script = self.get_script(alwayson_script_name, script_runner)
355
+ if alwayson_script is None:
356
+ raise HTTPException(status_code=422, detail=f"always on script {alwayson_script_name} not found")
357
+ # Selectable script in always on script param check
358
+ if alwayson_script.alwayson is False:
359
+ raise HTTPException(status_code=422, detail="Cannot have a selectable script in the always on scripts params")
360
+ # always on script with no arg should always run so you don't really need to add them to the requests
361
+ if "args" in request.alwayson_scripts[alwayson_script_name]:
362
+ # min between arg length in scriptrunner and arg length in the request
363
+ for idx in range(0, min((alwayson_script.args_to - alwayson_script.args_from), len(request.alwayson_scripts[alwayson_script_name]["args"]))):
364
+ script_args[alwayson_script.args_from + idx] = request.alwayson_scripts[alwayson_script_name]["args"][idx]
365
+ return script_args
366
+
367
+ def apply_infotext(self, request, tabname, *, script_runner=None, mentioned_script_args=None):
368
+ """Processes `infotext` field from the `request`, and sets other fields of the `request` accoring to what's in infotext.
369
+
370
+ If request already has a field set, and that field is encountered in infotext too, the value from infotext is ignored.
371
+
372
+ Additionally, fills `mentioned_script_args` dict with index: value pairs for script arguments read from infotext.
373
+ """
374
+
375
+ if not request.infotext:
376
+ return {}
377
+
378
+ possible_fields = infotext_utils.paste_fields[tabname]["fields"]
379
+ set_fields = request.model_dump(exclude_unset=True) if hasattr(request, "request") else request.dict(exclude_unset=True) # pydantic v1/v2 have differenrt names for this
380
+ params = infotext_utils.parse_generation_parameters(request.infotext)
381
+
382
+ def get_field_value(field, params):
383
+ value = field.function(params) if field.function else params.get(field.label)
384
+ if value is None:
385
+ return None
386
+
387
+ if field.api in request.__fields__:
388
+ target_type = request.__fields__[field.api].type_
389
+ else:
390
+ target_type = type(field.component.value)
391
+
392
+ if target_type == type(None):
393
+ return None
394
+
395
+ if isinstance(value, dict) and value.get('__type__') == 'generic_update': # this is a gradio.update rather than a value
396
+ value = value.get('value')
397
+
398
+ if value is not None and not isinstance(value, target_type):
399
+ value = target_type(value)
400
+
401
+ return value
402
+
403
+ for field in possible_fields:
404
+ if not field.api:
405
+ continue
406
+
407
+ if field.api in set_fields:
408
+ continue
409
+
410
+ value = get_field_value(field, params)
411
+ if value is not None:
412
+ setattr(request, field.api, value)
413
+
414
+ if request.override_settings is None:
415
+ request.override_settings = {}
416
+
417
+ overriden_settings = infotext_utils.get_override_settings(params)
418
+ for _, setting_name, value in overriden_settings:
419
+ if setting_name not in request.override_settings:
420
+ request.override_settings[setting_name] = value
421
+
422
+ if script_runner is not None and mentioned_script_args is not None:
423
+ indexes = {v: i for i, v in enumerate(script_runner.inputs)}
424
+ script_fields = ((field, indexes[field.component]) for field in possible_fields if field.component in indexes)
425
+
426
+ for field, index in script_fields:
427
+ value = get_field_value(field, params)
428
+
429
+ if value is None:
430
+ continue
431
+
432
+ mentioned_script_args[index] = value
433
+
434
+ return params
435
+
436
+ def text2imgapi(self, txt2imgreq: models.StableDiffusionTxt2ImgProcessingAPI):
437
+ task_id = txt2imgreq.force_task_id or create_task_id("txt2img")
438
+
439
+ script_runner = scripts.scripts_txt2img
440
+
441
+ infotext_script_args = {}
442
+ self.apply_infotext(txt2imgreq, "txt2img", script_runner=script_runner, mentioned_script_args=infotext_script_args)
443
+
444
+ selectable_scripts, selectable_script_idx = self.get_selectable_script(txt2imgreq.script_name, script_runner)
445
+
446
+ populate = txt2imgreq.copy(update={ # Override __init__ params
447
+ "sampler_name": validate_sampler_name(txt2imgreq.sampler_name or txt2imgreq.sampler_index),
448
+ "do_not_save_samples": not txt2imgreq.save_images,
449
+ "do_not_save_grid": not txt2imgreq.save_images,
450
+ })
451
+ if populate.sampler_name:
452
+ populate.sampler_index = None # prevent a warning later on
453
+
454
+ args = vars(populate)
455
+ args.pop('script_name', None)
456
+ args.pop('script_args', None) # will refeed them to the pipeline directly after initializing them
457
+ args.pop('alwayson_scripts', None)
458
+ args.pop('infotext', None)
459
+
460
+ script_args = self.init_script_args(txt2imgreq, self.default_script_arg_txt2img, selectable_scripts, selectable_script_idx, script_runner, input_script_args=infotext_script_args)
461
+
462
+ send_images = args.pop('send_images', True)
463
+ args.pop('save_images', None)
464
+
465
+ add_task_to_queue(task_id)
466
+
467
+ with self.queue_lock:
468
+ with closing(StableDiffusionProcessingTxt2Img(sd_model=shared.sd_model, **args)) as p:
469
+ p.is_api = True
470
+ p.scripts = script_runner
471
+ p.outpath_grids = opts.outdir_txt2img_grids
472
+ p.outpath_samples = opts.outdir_txt2img_samples
473
+
474
+ try:
475
+ shared.state.begin(job="scripts_txt2img")
476
+ start_task(task_id)
477
+ if selectable_scripts is not None:
478
+ p.script_args = script_args
479
+ processed = scripts.scripts_txt2img.run(p, *p.script_args) # Need to pass args as list here
480
+ else:
481
+ p.script_args = tuple(script_args) # Need to pass args as tuple here
482
+ processed = process_images(p)
483
+ finish_task(task_id)
484
+ finally:
485
+ shared.state.end()
486
+ shared.total_tqdm.clear()
487
+
488
+ b64images = [
489
+ encode_pil_to_base64(image)
490
+ for image in itertools.chain(processed.images, processed.extra_images)
491
+ if send_images
492
+ ]
493
+
494
+ return models.TextToImageResponse(images=b64images, parameters=vars(txt2imgreq), info=processed.js())
495
+
496
+ def text2imgapimod(self, txt2imgreq: models.StableDiffusionTxt2ImgProcessingAPI):
497
+ task_id = txt2imgreq.force_task_id or create_task_id("txt2img")
498
+
499
+ script_runner = scripts.scripts_txt2img
500
+
501
+ infotext_script_args = {}
502
+ self.apply_infotext(txt2imgreq, "txt2img", script_runner=script_runner, mentioned_script_args=infotext_script_args)
503
+
504
+ selectable_scripts, selectable_script_idx = self.get_selectable_script(txt2imgreq.script_name, script_runner)
505
+
506
+ populate = txt2imgreq.copy(update={ # Override __init__ params
507
+ "sampler_name": validate_sampler_name(txt2imgreq.sampler_name or txt2imgreq.sampler_index),
508
+ "do_not_save_samples": not txt2imgreq.save_images,
509
+ "do_not_save_grid": not txt2imgreq.save_images,
510
+ })
511
+ if populate.sampler_name:
512
+ populate.sampler_index = None # prevent a warning later on
513
+
514
+ args = vars(populate)
515
+ args.pop('script_name', None)
516
+ args.pop('script_args', None) # will refeed them to the pipeline directly after initializing them
517
+ args.pop('alwayson_scripts', None)
518
+ args.pop('infotext', None)
519
+
520
+ script_args = self.init_script_args(txt2imgreq, self.default_script_arg_txt2img, selectable_scripts, selectable_script_idx, script_runner, input_script_args=infotext_script_args)
521
+
522
+ send_images = args.pop('send_images', True)
523
+ args.pop('save_images', None)
524
+
525
+ add_task_to_queue(task_id)
526
+
527
+ with self.queue_lock:
528
+ with closing(StableDiffusionProcessingTxt2Img(sd_model=shared.sd_model, **args)) as p:
529
+ p.is_api = True
530
+ p.scripts = script_runner
531
+ p.outpath_grids = opts.outdir_txt2img_grids
532
+ p.outpath_samples = opts.outdir_txt2img_samples
533
+
534
+ try:
535
+ shared.state.begin(job="scripts_txt2img")
536
+ start_task(task_id)
537
+ if selectable_scripts is not None:
538
+ p.script_args = script_args
539
+ processed = scripts.scripts_txt2img.run(p, *p.script_args) # Need to pass args as list here
540
+ else:
541
+ p.script_args = tuple(script_args) # Need to pass args as tuple here
542
+ processed = process_images(p)
543
+ finish_task(task_id)
544
+ finally:
545
+ shared.state.end()
546
+ shared.total_tqdm.clear()
547
+
548
+ for image in itertools.chain(processed.images, processed.extra_images):
549
+ # <PIL.Image.Image image mode=RGB size=512x512 at 0x241AA93FD90>█
550
+ # save image and return path
551
+ temp_dir = "temp"
552
+ # Create folder
553
+ if not os.path.exists(temp_dir):
554
+ os.makedirs(temp_dir)
555
+
556
+ timestampp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
557
+ temp_file = os.path.join(temp_dir, f'temp_{timestampp}.png')
558
+ image.save(temp_file)
559
+
560
+ full_temp_path = os.path.abspath(temp_file)
561
+
562
+ return models.TextToImageResponseMod(image=full_temp_path)
563
+ # print(image)
564
+
565
+ b64images = [
566
+ encode_pil_to_base64(image)
567
+ for image in itertools.chain(processed.images, processed.extra_images)
568
+ if send_images
569
+ ]
570
+
571
+ def img2imgapi(self, img2imgreq: models.StableDiffusionImg2ImgProcessingAPI):
572
+ task_id = img2imgreq.force_task_id or create_task_id("img2img")
573
+
574
+ init_images = img2imgreq.init_images
575
+ if init_images is None:
576
+ raise HTTPException(status_code=404, detail="Init image not found")
577
+
578
+ mask = img2imgreq.mask
579
+ if mask:
580
+ mask = decode_base64_to_image(mask)
581
+
582
+ script_runner = scripts.scripts_img2img
583
+
584
+ infotext_script_args = {}
585
+ self.apply_infotext(img2imgreq, "img2img", script_runner=script_runner, mentioned_script_args=infotext_script_args)
586
+
587
+ selectable_scripts, selectable_script_idx = self.get_selectable_script(img2imgreq.script_name, script_runner)
588
+
589
+ populate = img2imgreq.copy(update={ # Override __init__ params
590
+ "sampler_name": validate_sampler_name(img2imgreq.sampler_name or img2imgreq.sampler_index),
591
+ "do_not_save_samples": not img2imgreq.save_images,
592
+ "do_not_save_grid": not img2imgreq.save_images,
593
+ "mask": mask,
594
+ })
595
+ if populate.sampler_name:
596
+ populate.sampler_index = None # prevent a warning later on
597
+
598
+ args = vars(populate)
599
+ args.pop('include_init_images', None) # this is meant to be done by "exclude": True in model, but it's for a reason that I cannot determine.
600
+ args.pop('script_name', None)
601
+ args.pop('script_args', None) # will refeed them to the pipeline directly after initializing them
602
+ args.pop('alwayson_scripts', None)
603
+ args.pop('infotext', None)
604
+
605
+ script_args = self.init_script_args(img2imgreq, self.default_script_arg_img2img, selectable_scripts, selectable_script_idx, script_runner, input_script_args=infotext_script_args)
606
+
607
+ send_images = args.pop('send_images', True)
608
+ args.pop('save_images', None)
609
+
610
+ add_task_to_queue(task_id)
611
+
612
+ with self.queue_lock:
613
+ with closing(StableDiffusionProcessingImg2Img(sd_model=shared.sd_model, **args)) as p:
614
+ p.init_images = [decode_base64_to_image(x) for x in init_images]
615
+ p.is_api = True
616
+ p.scripts = script_runner
617
+ p.outpath_grids = opts.outdir_img2img_grids
618
+ p.outpath_samples = opts.outdir_img2img_samples
619
+
620
+ try:
621
+ shared.state.begin(job="scripts_img2img")
622
+ start_task(task_id)
623
+ if selectable_scripts is not None:
624
+ p.script_args = script_args
625
+ processed = scripts.scripts_img2img.run(p, *p.script_args) # Need to pass args as list here
626
+ else:
627
+ p.script_args = tuple(script_args) # Need to pass args as tuple here
628
+ processed = process_images(p)
629
+ finish_task(task_id)
630
+ finally:
631
+ shared.state.end()
632
+ shared.total_tqdm.clear()
633
+
634
+ b64images = [
635
+ encode_pil_to_base64(image)
636
+ for image in itertools.chain(processed.images, processed.extra_images)
637
+ if send_images
638
+ ]
639
+
640
+ if not img2imgreq.include_init_images:
641
+ img2imgreq.init_images = None
642
+ img2imgreq.mask = None
643
+
644
+ return models.ImageToImageResponse(images=b64images, parameters=vars(img2imgreq), info=processed.js())
645
+
646
+ def extras_single_image_api(self, req: models.ExtrasSingleImageRequest):
647
+ reqDict = setUpscalers(req)
648
+
649
+ reqDict['image'] = decode_base64_to_image(reqDict['image'])
650
+
651
+ with self.queue_lock:
652
+ result = postprocessing.run_extras(extras_mode=0, image_folder="", input_dir="", output_dir="", save_output=False, **reqDict)
653
+
654
+ return models.ExtrasSingleImageResponse(image=encode_pil_to_base64(result[0][0]), html_info=result[1])
655
+
656
+ def extras_batch_images_api(self, req: models.ExtrasBatchImagesRequest):
657
+ reqDict = setUpscalers(req)
658
+
659
+ image_list = reqDict.pop('imageList', [])
660
+ image_folder = [decode_base64_to_image(x.data) for x in image_list]
661
+
662
+ with self.queue_lock:
663
+ result = postprocessing.run_extras(extras_mode=1, image_folder=image_folder, image="", input_dir="", output_dir="", save_output=False, **reqDict)
664
+
665
+ return models.ExtrasBatchImagesResponse(images=list(map(encode_pil_to_base64, result[0])), html_info=result[1])
666
+
667
+ def pnginfoapi(self, req: models.PNGInfoRequest):
668
+ image = decode_base64_to_image(req.image.strip())
669
+ if image is None:
670
+ return models.PNGInfoResponse(info="")
671
+
672
+ geninfo, items = images.read_info_from_image(image)
673
+ if geninfo is None:
674
+ geninfo = ""
675
+
676
+ params = infotext_utils.parse_generation_parameters(geninfo)
677
+ script_callbacks.infotext_pasted_callback(geninfo, params)
678
+
679
+ return models.PNGInfoResponse(info=geninfo, items=items, parameters=params)
680
+
681
+ def progressapi(self, req: models.ProgressRequest = Depends()):
682
+ # copy from check_progress_call of ui.py
683
+
684
+ if shared.state.job_count == 0:
685
+ return models.ProgressResponse(progress=0, eta_relative=0, state=shared.state.dict(), textinfo=shared.state.textinfo)
686
+
687
+ # avoid dividing zero
688
+ progress = 0.01
689
+
690
+ if shared.state.job_count > 0:
691
+ progress += shared.state.job_no / shared.state.job_count
692
+ if shared.state.sampling_steps > 0:
693
+ progress += 1 / shared.state.job_count * shared.state.sampling_step / shared.state.sampling_steps
694
+
695
+ time_since_start = time.time() - shared.state.time_start
696
+ eta = (time_since_start/progress)
697
+ eta_relative = eta-time_since_start
698
+
699
+ progress = min(progress, 1)
700
+
701
+ shared.state.set_current_image()
702
+
703
+ current_image = None
704
+ if shared.state.current_image and not req.skip_current_image:
705
+ current_image = encode_pil_to_base64(shared.state.current_image)
706
+
707
+ return models.ProgressResponse(progress=progress, eta_relative=eta_relative, state=shared.state.dict(), current_image=current_image, textinfo=shared.state.textinfo, current_task=current_task)
708
+
709
+ def interrogateapi(self, interrogatereq: models.InterrogateRequest):
710
+ image_b64 = interrogatereq.image
711
+ if image_b64 is None:
712
+ raise HTTPException(status_code=404, detail="Image not found")
713
+
714
+ img = decode_base64_to_image(image_b64)
715
+ img = img.convert('RGB')
716
+
717
+ # Override object param
718
+ with self.queue_lock:
719
+ if interrogatereq.model == "clip":
720
+ processed = shared.interrogator.interrogate(img)
721
+ elif interrogatereq.model == "deepdanbooru":
722
+ processed = deepbooru.model.tag(img)
723
+ else:
724
+ raise HTTPException(status_code=404, detail="Model not found")
725
+
726
+ return models.InterrogateResponse(caption=processed)
727
+
728
+ def interruptapi(self):
729
+ shared.state.interrupt()
730
+
731
+ return {}
732
+
733
+ def unloadapi(self):
734
+ sd_models.unload_model_weights()
735
+
736
+ return {}
737
+
738
+ def reloadapi(self):
739
+ sd_models.send_model_to_device(shared.sd_model)
740
+
741
+ return {}
742
+
743
+ def skip(self):
744
+ shared.state.skip()
745
+
746
+ def get_config(self):
747
+ options = {}
748
+ for key in shared.opts.data.keys():
749
+ metadata = shared.opts.data_labels.get(key)
750
+ if(metadata is not None):
751
+ options.update({key: shared.opts.data.get(key, shared.opts.data_labels.get(key).default)})
752
+ else:
753
+ options.update({key: shared.opts.data.get(key, None)})
754
+
755
+ return options
756
+
757
+ def set_config(self, req: dict[str, Any]):
758
+ checkpoint_name = req.get("sd_model_checkpoint", None)
759
+ if checkpoint_name is not None and checkpoint_name not in sd_models.checkpoint_aliases:
760
+ raise RuntimeError(f"model {checkpoint_name!r} not found")
761
+
762
+ for k, v in req.items():
763
+ shared.opts.set(k, v, is_api=True)
764
+
765
+ shared.opts.save(shared.config_filename)
766
+ return
767
+
768
+ def get_cmd_flags(self):
769
+ return vars(shared.cmd_opts)
770
+
771
+ def get_samplers(self):
772
+ return [{"name": sampler[0], "aliases":sampler[2], "options":sampler[3]} for sampler in sd_samplers.all_samplers]
773
+
774
+ def get_upscalers(self):
775
+ return [
776
+ {
777
+ "name": upscaler.name,
778
+ "model_name": upscaler.scaler.model_name,
779
+ "model_path": upscaler.data_path,
780
+ "model_url": None,
781
+ "scale": upscaler.scale,
782
+ }
783
+ for upscaler in shared.sd_upscalers
784
+ ]
785
+
786
+ def get_latent_upscale_modes(self):
787
+ return [
788
+ {
789
+ "name": upscale_mode,
790
+ }
791
+ for upscale_mode in [*(shared.latent_upscale_modes or {})]
792
+ ]
793
+
794
+ def get_sd_models(self):
795
+ import modules.sd_models as sd_models
796
+ return [{"title": x.title, "model_name": x.model_name, "hash": x.shorthash, "sha256": x.sha256, "filename": x.filename, "config": find_checkpoint_config_near_filename(x)} for x in sd_models.checkpoints_list.values()]
797
+
798
+ def get_sd_vaes(self):
799
+ import modules.sd_vae as sd_vae
800
+ return [{"model_name": x, "filename": sd_vae.vae_dict[x]} for x in sd_vae.vae_dict.keys()]
801
+
802
+ def get_hypernetworks(self):
803
+ return [{"name": name, "path": shared.hypernetworks[name]} for name in shared.hypernetworks]
804
+
805
+ def get_face_restorers(self):
806
+ return [{"name":x.name(), "cmd_dir": getattr(x, "cmd_dir", None)} for x in shared.face_restorers]
807
+
808
+ def get_realesrgan_models(self):
809
+ return [{"name":x.name,"path":x.data_path, "scale":x.scale} for x in get_realesrgan_models(None)]
810
+
811
+ def get_prompt_styles(self):
812
+ styleList = []
813
+ for k in shared.prompt_styles.styles:
814
+ style = shared.prompt_styles.styles[k]
815
+ styleList.append({"name":style[0], "prompt": style[1], "negative_prompt": style[2]})
816
+
817
+ return styleList
818
+
819
+ def get_embeddings(self):
820
+ db = sd_hijack.model_hijack.embedding_db
821
+
822
+ def convert_embedding(embedding):
823
+ return {
824
+ "step": embedding.step,
825
+ "sd_checkpoint": embedding.sd_checkpoint,
826
+ "sd_checkpoint_name": embedding.sd_checkpoint_name,
827
+ "shape": embedding.shape,
828
+ "vectors": embedding.vectors,
829
+ }
830
+
831
+ def convert_embeddings(embeddings):
832
+ return {embedding.name: convert_embedding(embedding) for embedding in embeddings.values()}
833
+
834
+ return {
835
+ "loaded": convert_embeddings(db.word_embeddings),
836
+ "skipped": convert_embeddings(db.skipped_embeddings),
837
+ }
838
+
839
+ def refresh_embeddings(self):
840
+ with self.queue_lock:
841
+ sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings(force_reload=True)
842
+
843
+ def refresh_checkpoints(self):
844
+ with self.queue_lock:
845
+ shared.refresh_checkpoints()
846
+
847
+ def refresh_vae(self):
848
+ with self.queue_lock:
849
+ shared_items.refresh_vae_list()
850
+
851
+ def create_embedding(self, args: dict):
852
+ try:
853
+ shared.state.begin(job="create_embedding")
854
+ filename = create_embedding(**args) # create empty embedding
855
+ sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings() # reload embeddings so new one can be immediately used
856
+ return models.CreateResponse(info=f"create embedding filename: {filename}")
857
+ except AssertionError as e:
858
+ return models.TrainResponse(info=f"create embedding error: {e}")
859
+ finally:
860
+ shared.state.end()
861
+
862
+
863
+ def create_hypernetwork(self, args: dict):
864
+ try:
865
+ shared.state.begin(job="create_hypernetwork")
866
+ filename = create_hypernetwork(**args) # create empty embedding
867
+ return models.CreateResponse(info=f"create hypernetwork filename: {filename}")
868
+ except AssertionError as e:
869
+ return models.TrainResponse(info=f"create hypernetwork error: {e}")
870
+ finally:
871
+ shared.state.end()
872
+
873
+ def train_embedding(self, args: dict):
874
+ try:
875
+ shared.state.begin(job="train_embedding")
876
+ apply_optimizations = shared.opts.training_xattention_optimizations
877
+ error = None
878
+ filename = ''
879
+ if not apply_optimizations:
880
+ sd_hijack.undo_optimizations()
881
+ try:
882
+ embedding, filename = train_embedding(**args) # can take a long time to complete
883
+ except Exception as e:
884
+ error = e
885
+ finally:
886
+ if not apply_optimizations:
887
+ sd_hijack.apply_optimizations()
888
+ return models.TrainResponse(info=f"train embedding complete: filename: {filename} error: {error}")
889
+ except Exception as msg:
890
+ return models.TrainResponse(info=f"train embedding error: {msg}")
891
+ finally:
892
+ shared.state.end()
893
+
894
+ def train_hypernetwork(self, args: dict):
895
+ try:
896
+ shared.state.begin(job="train_hypernetwork")
897
+ shared.loaded_hypernetworks = []
898
+ apply_optimizations = shared.opts.training_xattention_optimizations
899
+ error = None
900
+ filename = ''
901
+ if not apply_optimizations:
902
+ sd_hijack.undo_optimizations()
903
+ try:
904
+ hypernetwork, filename = train_hypernetwork(**args)
905
+ except Exception as e:
906
+ error = e
907
+ finally:
908
+ shared.sd_model.cond_stage_model.to(devices.device)
909
+ shared.sd_model.first_stage_model.to(devices.device)
910
+ if not apply_optimizations:
911
+ sd_hijack.apply_optimizations()
912
+ shared.state.end()
913
+ return models.TrainResponse(info=f"train embedding complete: filename: {filename} error: {error}")
914
+ except Exception as exc:
915
+ return models.TrainResponse(info=f"train embedding error: {exc}")
916
+ finally:
917
+ shared.state.end()
918
+
919
+ def get_memory(self):
920
+ try:
921
+ import os
922
+ import psutil
923
+ process = psutil.Process(os.getpid())
924
+ res = process.memory_info() # only rss is cross-platform guaranteed so we dont rely on other values
925
+ ram_total = 100 * res.rss / process.memory_percent() # and total memory is calculated as actual value is not cross-platform safe
926
+ ram = { 'free': ram_total - res.rss, 'used': res.rss, 'total': ram_total }
927
+ except Exception as err:
928
+ ram = { 'error': f'{err}' }
929
+ try:
930
+ import torch
931
+ if torch.cuda.is_available():
932
+ s = torch.cuda.mem_get_info()
933
+ system = { 'free': s[0], 'used': s[1] - s[0], 'total': s[1] }
934
+ s = dict(torch.cuda.memory_stats(shared.device))
935
+ allocated = { 'current': s['allocated_bytes.all.current'], 'peak': s['allocated_bytes.all.peak'] }
936
+ reserved = { 'current': s['reserved_bytes.all.current'], 'peak': s['reserved_bytes.all.peak'] }
937
+ active = { 'current': s['active_bytes.all.current'], 'peak': s['active_bytes.all.peak'] }
938
+ inactive = { 'current': s['inactive_split_bytes.all.current'], 'peak': s['inactive_split_bytes.all.peak'] }
939
+ warnings = { 'retries': s['num_alloc_retries'], 'oom': s['num_ooms'] }
940
+ cuda = {
941
+ 'system': system,
942
+ 'active': active,
943
+ 'allocated': allocated,
944
+ 'reserved': reserved,
945
+ 'inactive': inactive,
946
+ 'events': warnings,
947
+ }
948
+ else:
949
+ cuda = {'error': 'unavailable'}
950
+ except Exception as err:
951
+ cuda = {'error': f'{err}'}
952
+ return models.MemoryResponse(ram=ram, cuda=cuda)
953
+
954
+ def get_extensions_list(self):
955
+ from modules import extensions
956
+ extensions.list_extensions()
957
+ ext_list = []
958
+ for ext in extensions.extensions:
959
+ ext: extensions.Extension
960
+ ext.read_info_from_repo()
961
+ if ext.remote is not None:
962
+ ext_list.append({
963
+ "name": ext.name,
964
+ "remote": ext.remote,
965
+ "branch": ext.branch,
966
+ "commit_hash":ext.commit_hash,
967
+ "commit_date":ext.commit_date,
968
+ "version":ext.version,
969
+ "enabled":ext.enabled
970
+ })
971
+ return ext_list
972
+
973
+ def launch(self, server_name, port, root_path):
974
+ self.app.include_router(self.router)
975
+ uvicorn.run(
976
+ self.app,
977
+ host=server_name,
978
+ port=port,
979
+ timeout_keep_alive=shared.cmd_opts.timeout_keep_alive,
980
+ root_path=root_path,
981
+ ssl_keyfile=shared.cmd_opts.tls_keyfile,
982
+ ssl_certfile=shared.cmd_opts.tls_certfile
983
+ )
984
+
985
+ def kill_webui(self):
986
+ restart.stop_program()
987
+
988
+ def restart_webui(self):
989
+ if restart.is_restartable():
990
+ restart.restart_program()
991
+ return Response(status_code=501)
992
+
993
+ def stop_webui(request):
994
+ shared.state.server_command = "stop"
995
+ return Response("Stopping.")
996
+
api/models.py ADDED
@@ -0,0 +1,326 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 TextToImageResponseMod(BaseModel):
145
+ # Изменяем под формат изображения, не base64
146
+ image: str
147
+
148
+ class ExtrasBaseRequest(BaseModel):
149
+ 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.")
150
+ show_extras_results: bool = Field(default=True, title="Show results", description="Should the backend return the generated image?")
151
+ 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.")
152
+ 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.")
153
+ 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.")
154
+ 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.")
155
+ 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.")
156
+ 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.")
157
+ upscaling_crop: bool = Field(default=True, title="Crop to fit", description="Should the upscaler crop the image to fit in the chosen size?")
158
+ 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])}")
159
+ 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])}")
160
+ 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.")
161
+ upscale_first: bool = Field(default=False, title="Upscale first", description="Should the upscaler run before restoring faces?")
162
+
163
+ class ExtraBaseResponse(BaseModel):
164
+ html_info: str = Field(title="HTML info", description="A series of HTML tags containing the process info.")
165
+
166
+ class ExtrasSingleImageRequest(ExtrasBaseRequest):
167
+ image: str = Field(default="", title="Image", description="Image to work on, must be a Base64 string containing the image's data.")
168
+
169
+ class ExtrasSingleImageResponse(ExtraBaseResponse):
170
+ image: str = Field(default=None, title="Image", description="The generated image in base64 format.")
171
+
172
+ class FileData(BaseModel):
173
+ data: str = Field(title="File data", description="Base64 representation of the file")
174
+ name: str = Field(title="File name")
175
+
176
+ class ExtrasBatchImagesRequest(ExtrasBaseRequest):
177
+ imageList: list[FileData] = Field(title="Images", description="List of images to work on. Must be Base64 strings")
178
+
179
+ class ExtrasBatchImagesResponse(ExtraBaseResponse):
180
+ images: list[str] = Field(title="Images", description="The generated images in base64 format.")
181
+
182
+ class PNGInfoRequest(BaseModel):
183
+ image: str = Field(title="Image", description="The base64 encoded PNG image")
184
+
185
+ class PNGInfoResponse(BaseModel):
186
+ info: str = Field(title="Image info", description="A string with the parameters used to generate the image")
187
+ items: dict = Field(title="Items", description="A dictionary containing all the other fields the image had")
188
+ parameters: dict = Field(title="Parameters", description="A dictionary with parsed generation info fields")
189
+
190
+ class ProgressRequest(BaseModel):
191
+ skip_current_image: bool = Field(default=False, title="Skip current image", description="Skip current image serialization")
192
+
193
+ class ProgressResponse(BaseModel):
194
+ progress: float = Field(title="Progress", description="The progress with a range of 0 to 1")
195
+ eta_relative: float = Field(title="ETA in secs")
196
+ state: dict = Field(title="State", description="The current state snapshot")
197
+ 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.")
198
+ textinfo: str = Field(default=None, title="Info text", description="Info text used by WebUI.")
199
+
200
+ class InterrogateRequest(BaseModel):
201
+ image: str = Field(default="", title="Image", description="Image to work on, must be a Base64 string containing the image's data.")
202
+ model: str = Field(default="clip", title="Model", description="The interrogate model used.")
203
+
204
+ class InterrogateResponse(BaseModel):
205
+ caption: str = Field(default=None, title="Caption", description="The generated caption for the image.")
206
+
207
+ class TrainResponse(BaseModel):
208
+ info: str = Field(title="Train info", description="Response string from train embedding or hypernetwork task.")
209
+
210
+ class CreateResponse(BaseModel):
211
+ info: str = Field(title="Create info", description="Response string from create embedding or hypernetwork task.")
212
+
213
+ fields = {}
214
+ for key, metadata in opts.data_labels.items():
215
+ value = opts.data.get(key)
216
+ optType = opts.typemap.get(type(metadata.default), type(metadata.default)) if metadata.default else Any
217
+
218
+ if metadata is not None:
219
+ fields.update({key: (Optional[optType], Field(default=metadata.default, description=metadata.label))})
220
+ else:
221
+ fields.update({key: (Optional[optType], Field())})
222
+
223
+ OptionsModel = create_model("Options", **fields)
224
+
225
+ flags = {}
226
+ _options = vars(parser)['_option_string_actions']
227
+ for key in _options:
228
+ if(_options[key].dest != 'help'):
229
+ flag = _options[key]
230
+ _type = str
231
+ if _options[key].default is not None:
232
+ _type = type(_options[key].default)
233
+ flags.update({flag.dest: (_type, Field(default=flag.default, description=flag.help))})
234
+
235
+ FlagsModel = create_model("Flags", **flags)
236
+
237
+ class SamplerItem(BaseModel):
238
+ name: str = Field(title="Name")
239
+ aliases: list[str] = Field(title="Aliases")
240
+ options: dict[str, str] = Field(title="Options")
241
+
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
+
249
+ class LatentUpscalerModeItem(BaseModel):
250
+ name: str = Field(title="Name")
251
+
252
+ class SDModelItem(BaseModel):
253
+ title: str = Field(title="Title")
254
+ model_name: str = Field(title="Model Name")
255
+ hash: Optional[str] = Field(title="Short hash")
256
+ sha256: Optional[str] = Field(title="sha256 hash")
257
+ filename: str = Field(title="Filename")
258
+ config: Optional[str] = Field(title="Config file")
259
+
260
+ class SDVaeItem(BaseModel):
261
+ model_name: str = Field(title="Model Name")
262
+ filename: str = Field(title="Filename")
263
+
264
+ class HypernetworkItem(BaseModel):
265
+ name: str = Field(title="Name")
266
+ path: Optional[str] = Field(title="Path")
267
+
268
+ class FaceRestorerItem(BaseModel):
269
+ name: str = Field(title="Name")
270
+ cmd_dir: Optional[str] = Field(title="Path")
271
+
272
+ class RealesrganItem(BaseModel):
273
+ name: str = Field(title="Name")
274
+ path: Optional[str] = Field(title="Path")
275
+ scale: Optional[int] = Field(title="Scale")
276
+
277
+ class PromptStyleItem(BaseModel):
278
+ name: str = Field(title="Name")
279
+ prompt: Optional[str] = Field(title="Prompt")
280
+ negative_prompt: Optional[str] = Field(title="Negative Prompt")
281
+
282
+
283
+ class EmbeddingItem(BaseModel):
284
+ step: Optional[int] = Field(title="Step", description="The number of steps that were used to train this embedding, if available")
285
+ sd_checkpoint: Optional[str] = Field(title="SD Checkpoint", description="The hash of the checkpoint this embedding was trained on, if available")
286
+ 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")
287
+ shape: int = Field(title="Shape", description="The length of each individual vector in the embedding")
288
+ vectors: int = Field(title="Vectors", description="The number of vectors in the embedding")
289
+
290
+ class EmbeddingsResponse(BaseModel):
291
+ loaded: dict[str, EmbeddingItem] = Field(title="Loaded", description="Embeddings loaded for the current model")
292
+ skipped: dict[str, EmbeddingItem] = Field(title="Skipped", description="Embeddings skipped for the current model (likely due to architecture incompatibility)")
293
+
294
+ class MemoryResponse(BaseModel):
295
+ ram: dict = Field(title="RAM", description="System memory stats")
296
+ cuda: dict = Field(title="CUDA", description="nVidia CUDA memory stats")
297
+
298
+
299
+ class ScriptsList(BaseModel):
300
+ txt2img: list = Field(default=None, title="Txt2img", description="Titles of scripts (txt2img)")
301
+ img2img: list = Field(default=None, title="Img2img", description="Titles of scripts (img2img)")
302
+
303
+
304
+ class ScriptArg(BaseModel):
305
+ label: str = Field(default=None, title="Label", description="Name of the argument in UI")
306
+ value: Optional[Any] = Field(default=None, title="Value", description="Default value of the argument")
307
+ minimum: Optional[Any] = Field(default=None, title="Minimum", description="Minimum allowed value for the argumentin UI")
308
+ maximum: Optional[Any] = Field(default=None, title="Minimum", description="Maximum allowed value for the argumentin UI")
309
+ step: Optional[Any] = Field(default=None, title="Minimum", description="Step for changing value of the argumentin UI")
310
+ choices: Optional[list[str]] = Field(default=None, title="Choices", description="Possible values for the argument")
311
+
312
+
313
+ class ScriptInfo(BaseModel):
314
+ name: str = Field(default=None, title="Name", description="Script name")
315
+ is_alwayson: bool = Field(default=None, title="IsAlwayson", description="Flag specifying whether this script is an alwayson script")
316
+ is_img2img: bool = Field(default=None, title="IsImg2img", description="Flag specifying whether this script is an img2img script")
317
+ args: list[ScriptArg] = Field(title="Arguments", description="List of script's arguments")
318
+
319
+ class ExtensionItem(BaseModel):
320
+ name: str = Field(title="Name", description="Extension name")
321
+ remote: str = Field(title="Remote", description="Extension Repository URL")
322
+ branch: str = Field(title="Branch", description="Extension Repository Branch")
323
+ commit_hash: str = Field(title="Commit Hash", description="Extension Repository Commit Hash")
324
+ version: str = Field(title="Version", description="Extension Version")
325
+ commit_date: str = Field(title="Commit Date", description="Extension Repository Commit Date")
326
+ enabled: bool = Field(title="Enabled", description="Flag specifying whether this extension is enabled")
config.json ADDED
@@ -0,0 +1,327 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "ldsr_steps": 100,
3
+ "ldsr_cached": false,
4
+ "SCUNET_tile": 256,
5
+ "SCUNET_tile_overlap": 8,
6
+ "SWIN_tile": 192,
7
+ "SWIN_tile_overlap": 8,
8
+ "SWIN_torch_compile": false,
9
+ "control_net_detectedmap_dir": "detected_maps",
10
+ "control_net_models_path": "",
11
+ "control_net_modules_path": "",
12
+ "control_net_unit_count": 3,
13
+ "control_net_model_cache_size": 5,
14
+ "control_net_no_detectmap": false,
15
+ "control_net_detectmap_autosaving": false,
16
+ "control_net_allow_script_control": false,
17
+ "control_net_sync_field_args": true,
18
+ "controlnet_show_batch_images_in_ui": false,
19
+ "controlnet_increment_seed_during_batch": false,
20
+ "controlnet_disable_openpose_edit": false,
21
+ "controlnet_disable_photopea_edit": false,
22
+ "controlnet_photopea_warning": true,
23
+ "controlnet_input_thumbnail": true,
24
+ "sd_checkpoint_hash": "0fe2e39405369d15d576f0f8bf1405e53899613711f867c528d2a0d57fefba48",
25
+ "sd_model_checkpoint": "moxieDiffusionXL_v16.safetensors",
26
+ "CLIP_stop_at_last_layers": 2,
27
+ "sd_vae": "sdxl_vae.safetensors",
28
+ "api_display_include_base64_images": false,
29
+ "outdir_samples": "",
30
+ "outdir_txt2img_samples": "output\\txt2img-images",
31
+ "outdir_img2img_samples": "output\\img2img-images",
32
+ "outdir_extras_samples": "output\\extras-images",
33
+ "outdir_grids": "",
34
+ "outdir_txt2img_grids": "output\\txt2img-grids",
35
+ "outdir_img2img_grids": "output\\img2img-grids",
36
+ "outdir_save": "log\\images",
37
+ "outdir_init_images": "output\\init-images",
38
+ "samples_save": true,
39
+ "samples_format": "png",
40
+ "samples_filename_pattern": "",
41
+ "save_images_add_number": true,
42
+ "save_images_replace_action": "Replace",
43
+ "grid_save": true,
44
+ "grid_format": "png",
45
+ "grid_extended_filename": false,
46
+ "grid_only_if_multiple": true,
47
+ "grid_prevent_empty_spots": false,
48
+ "grid_zip_filename_pattern": "",
49
+ "n_rows": -1,
50
+ "font": "",
51
+ "grid_text_active_color": "#000000",
52
+ "grid_text_inactive_color": "#999999",
53
+ "grid_background_color": "#ffffff",
54
+ "save_images_before_face_restoration": false,
55
+ "save_images_before_highres_fix": false,
56
+ "save_images_before_color_correction": false,
57
+ "save_mask": false,
58
+ "save_mask_composite": false,
59
+ "jpeg_quality": 80,
60
+ "webp_lossless": false,
61
+ "export_for_4chan": true,
62
+ "img_downscale_threshold": 4.0,
63
+ "target_side_length": 4000.0,
64
+ "img_max_size_mp": 200.0,
65
+ "use_original_name_batch": true,
66
+ "use_upscaler_name_as_suffix": true,
67
+ "save_selected_only": true,
68
+ "save_init_img": false,
69
+ "temp_dir": "",
70
+ "clean_temp_dir_at_start": false,
71
+ "save_incomplete_images": false,
72
+ "notification_audio": true,
73
+ "notification_volume": 100,
74
+ "save_to_dirs": true,
75
+ "grid_save_to_dirs": true,
76
+ "use_save_to_dirs_for_ui": false,
77
+ "directories_filename_pattern": "[date]",
78
+ "directories_max_prompt_words": 8,
79
+ "auto_backcompat": true,
80
+ "use_old_emphasis_implementation": false,
81
+ "use_old_karras_scheduler_sigmas": false,
82
+ "no_dpmpp_sde_batch_determinism": false,
83
+ "use_old_hires_fix_width_height": false,
84
+ "dont_fix_second_order_samplers_schedule": false,
85
+ "hires_fix_use_firstpass_conds": false,
86
+ "use_old_scheduling": false,
87
+ "use_downcasted_alpha_bar": false,
88
+ "lora_functional": false,
89
+ "extra_networks_show_hidden_directories": true,
90
+ "extra_networks_dir_button_function": false,
91
+ "extra_networks_hidden_models": "When searched",
92
+ "extra_networks_default_multiplier": 1,
93
+ "extra_networks_card_width": 0.0,
94
+ "extra_networks_card_height": 0.0,
95
+ "extra_networks_card_text_scale": 1,
96
+ "extra_networks_card_show_desc": true,
97
+ "extra_networks_card_description_is_html": false,
98
+ "extra_networks_card_order_field": "Path",
99
+ "extra_networks_card_order": "Ascending",
100
+ "extra_networks_tree_view_default_enabled": false,
101
+ "extra_networks_add_text_separator": " ",
102
+ "ui_extra_networks_tab_reorder": "",
103
+ "textual_inversion_print_at_load": false,
104
+ "textual_inversion_add_hashes_to_infotext": true,
105
+ "sd_hypernetwork": "None",
106
+ "sd_lora": "None",
107
+ "lora_preferred_name": "Alias from file",
108
+ "lora_add_hashes_to_infotext": true,
109
+ "lora_show_all": false,
110
+ "lora_hide_unknown_for_versions": [],
111
+ "lora_in_memory_limit": 0,
112
+ "lora_not_found_warning_console": false,
113
+ "lora_not_found_gradio_warning": false,
114
+ "cross_attention_optimization": "Automatic",
115
+ "s_min_uncond": 0,
116
+ "token_merging_ratio": 0,
117
+ "token_merging_ratio_img2img": 0,
118
+ "token_merging_ratio_hr": 0,
119
+ "pad_cond_uncond": false,
120
+ "pad_cond_uncond_v0": false,
121
+ "persistent_cond_cache": true,
122
+ "batch_cond_uncond": true,
123
+ "fp8_storage": "Disable",
124
+ "cache_fp16_weight": false,
125
+ "hide_samplers": [],
126
+ "eta_ddim": 0,
127
+ "eta_ancestral": 1,
128
+ "ddim_discretize": "uniform",
129
+ "s_churn": 0,
130
+ "s_tmin": 0,
131
+ "s_tmax": 0,
132
+ "s_noise": 1,
133
+ "k_sched_type": "Automatic",
134
+ "sigma_min": 0.0,
135
+ "sigma_max": 0.0,
136
+ "rho": 0.0,
137
+ "eta_noise_seed_delta": 0,
138
+ "always_discard_next_to_last_sigma": false,
139
+ "sgm_noise_multiplier": false,
140
+ "uni_pc_variant": "bh1",
141
+ "uni_pc_skip_type": "time_uniform",
142
+ "uni_pc_order": 3,
143
+ "uni_pc_lower_order_final": true,
144
+ "sd_noise_schedule": "Default",
145
+ "sd_checkpoints_limit": 1,
146
+ "sd_checkpoints_keep_in_cpu": true,
147
+ "sd_checkpoint_cache": 0,
148
+ "sd_unet": "Automatic",
149
+ "enable_quantization": false,
150
+ "emphasis": "Original",
151
+ "enable_batch_seeds": true,
152
+ "comma_padding_backtrack": 20,
153
+ "upcast_attn": false,
154
+ "randn_source": "GPU",
155
+ "tiling": false,
156
+ "hires_fix_refiner_pass": "second pass",
157
+ "enable_prompt_comments": true,
158
+ "sdxl_crop_top": 0.0,
159
+ "sdxl_crop_left": 0.0,
160
+ "sdxl_refiner_low_aesthetic_score": 2.5,
161
+ "sdxl_refiner_high_aesthetic_score": 6.0,
162
+ "sd_vae_checkpoint_cache": 0,
163
+ "sd_vae_overrides_per_model_preferences": true,
164
+ "auto_vae_precision_bfloat16": false,
165
+ "auto_vae_precision": true,
166
+ "sd_vae_encode_method": "Full",
167
+ "sd_vae_decode_method": "Full",
168
+ "inpainting_mask_weight": 1,
169
+ "initial_noise_multiplier": 1,
170
+ "img2img_extra_noise": 0,
171
+ "img2img_color_correction": false,
172
+ "img2img_fix_steps": false,
173
+ "img2img_background_color": "#ffffff",
174
+ "img2img_editor_height": 720,
175
+ "img2img_sketch_default_brush_color": "#ffffff",
176
+ "img2img_inpaint_mask_brush_color": "#ffffff",
177
+ "img2img_inpaint_sketch_default_brush_color": "#ffffff",
178
+ "return_mask": false,
179
+ "return_mask_composite": false,
180
+ "img2img_batch_show_results_limit": 32,
181
+ "overlay_inpaint": true,
182
+ "return_grid": true,
183
+ "do_not_show_images": false,
184
+ "js_modal_lightbox": true,
185
+ "js_modal_lightbox_initially_zoomed": true,
186
+ "js_modal_lightbox_gamepad": false,
187
+ "js_modal_lightbox_gamepad_repeat": 250.0,
188
+ "sd_webui_modal_lightbox_icon_opacity": 1,
189
+ "sd_webui_modal_lightbox_toolbar_opacity": 0.9,
190
+ "gallery_height": "",
191
+ "open_dir_button_choice": "Subdirectory",
192
+ "enable_pnginfo": true,
193
+ "save_txt": false,
194
+ "add_model_name_to_info": true,
195
+ "add_model_hash_to_info": true,
196
+ "add_vae_name_to_info": true,
197
+ "add_vae_hash_to_info": true,
198
+ "add_user_name_to_info": false,
199
+ "add_version_to_infotext": true,
200
+ "disable_weights_auto_swap": true,
201
+ "infotext_skip_pasting": [],
202
+ "infotext_styles": "Apply if any",
203
+ "show_progressbar": true,
204
+ "live_previews_enable": true,
205
+ "live_previews_image_format": "png",
206
+ "show_progress_grid": true,
207
+ "show_progress_every_n_steps": 10,
208
+ "show_progress_type": "Approx NN",
209
+ "live_preview_allow_lowvram_full": false,
210
+ "live_preview_content": "Prompt",
211
+ "live_preview_refresh_period": 1000.0,
212
+ "live_preview_fast_interrupt": false,
213
+ "js_live_preview_in_modal_lightbox": false,
214
+ "keyedit_precision_attention": 0.1,
215
+ "keyedit_precision_extra": 0.05,
216
+ "keyedit_delimiters": ".,\\/!?%^*;:{}=`~() ",
217
+ "keyedit_delimiters_whitespace": [
218
+ "Tab",
219
+ "Carriage Return",
220
+ "Line Feed"
221
+ ],
222
+ "keyedit_move": true,
223
+ "disable_token_counters": false,
224
+ "include_styles_into_token_counters": true,
225
+ "extra_options_txt2img": [],
226
+ "extra_options_img2img": [],
227
+ "extra_options_cols": 1,
228
+ "extra_options_accordion": false,
229
+ "compact_prompt_box": false,
230
+ "samplers_in_dropdown": true,
231
+ "dimensions_and_batch_together": true,
232
+ "sd_checkpoint_dropdown_use_short": false,
233
+ "hires_fix_show_sampler": false,
234
+ "hires_fix_show_prompts": false,
235
+ "txt2img_settings_accordion": false,
236
+ "img2img_settings_accordion": false,
237
+ "interrupt_after_current": true,
238
+ "localization": "None",
239
+ "quicksettings_list": [
240
+ "sd_model_checkpoint",
241
+ "sd_vae",
242
+ "CLIP_stop_at_last_layers"
243
+ ],
244
+ "ui_tab_order": [],
245
+ "hidden_tabs": [],
246
+ "ui_reorder_list": [],
247
+ "gradio_theme": "Default",
248
+ "gradio_themes_cache": true,
249
+ "show_progress_in_title": true,
250
+ "send_seed": true,
251
+ "send_size": true,
252
+ "api_enable_requests": true,
253
+ "api_forbid_local_requests": true,
254
+ "api_useragent": "",
255
+ "auto_launch_browser": "Local",
256
+ "enable_console_prompts": false,
257
+ "show_warnings": false,
258
+ "show_gradio_deprecation_warnings": true,
259
+ "memmon_poll_rate": 8,
260
+ "samples_log_stdout": false,
261
+ "multiple_tqdm": true,
262
+ "enable_upscale_progressbar": true,
263
+ "print_hypernet_extra": false,
264
+ "list_hidden_files": true,
265
+ "disable_mmap_load_safetensors": false,
266
+ "hide_ldm_prints": true,
267
+ "dump_stacks_on_signal": false,
268
+ "face_restoration": false,
269
+ "face_restoration_model": "CodeFormer",
270
+ "code_former_weight": 0.5,
271
+ "face_restoration_unload": false,
272
+ "postprocessing_enable_in_main_ui": [],
273
+ "postprocessing_operation_order": [],
274
+ "upscaling_max_images_in_cache": 5,
275
+ "postprocessing_existing_caption_action": "Ignore",
276
+ "ESRGAN_tile": 192,
277
+ "ESRGAN_tile_overlap": 8,
278
+ "realesrgan_enabled_models": [
279
+ "R-ESRGAN 4x+",
280
+ "R-ESRGAN 4x+ Anime6B"
281
+ ],
282
+ "dat_enabled_models": [
283
+ "DAT x2",
284
+ "DAT x3",
285
+ "DAT x4"
286
+ ],
287
+ "DAT_tile": 192,
288
+ "DAT_tile_overlap": 8,
289
+ "unload_models_when_training": false,
290
+ "pin_memory": false,
291
+ "save_optimizer_state": false,
292
+ "save_training_settings_to_txt": true,
293
+ "dataset_filename_word_regex": "",
294
+ "dataset_filename_join_string": " ",
295
+ "training_image_repeats_per_epoch": 1,
296
+ "training_write_csv_every": 500.0,
297
+ "training_xattention_optimizations": false,
298
+ "training_enable_tensorboard": false,
299
+ "training_tensorboard_save_images": false,
300
+ "training_tensorboard_flush_every": 120.0,
301
+ "canvas_hotkey_zoom": "Alt",
302
+ "canvas_hotkey_adjust": "Ctrl",
303
+ "canvas_hotkey_shrink_brush": "Q",
304
+ "canvas_hotkey_grow_brush": "W",
305
+ "canvas_hotkey_move": "F",
306
+ "canvas_hotkey_fullscreen": "S",
307
+ "canvas_hotkey_reset": "R",
308
+ "canvas_hotkey_overlap": "O",
309
+ "canvas_show_tooltip": true,
310
+ "canvas_auto_expand": true,
311
+ "canvas_blur_prompt": false,
312
+ "canvas_disabled_functions": [
313
+ "Overlap"
314
+ ],
315
+ "interrogate_keep_models_in_memory": false,
316
+ "interrogate_return_ranks": false,
317
+ "interrogate_clip_num_beams": 1,
318
+ "interrogate_clip_min_length": 24,
319
+ "interrogate_clip_max_length": 48,
320
+ "interrogate_clip_dict_limit": 1500.0,
321
+ "interrogate_clip_skip_categories": [],
322
+ "interrogate_deepbooru_score_threshold": 0.5,
323
+ "deepbooru_sort_alpha": true,
324
+ "deepbooru_use_spaces": true,
325
+ "deepbooru_escape": true,
326
+ "deepbooru_filter_tags": ""
327
+ }
models/ControlNet/diffusion_pytorch_model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c8127be9f174101ebdafee9964d856b49b634435cf6daa396d3f593cf0bbbb05
3
+ size 2502139136
models/ControlNet/ip-adapter.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:02b3618e36d803784166660520098089a81388e61a93ef8002aa79a5b1c546e1
3
+ size 1691134141
models/ESRGAN/4x_NMKD-Siax_2000k.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:560424d9f68625713fc47e9e7289a98aabe1d744e1cd6a9ae5a35e9957fd127e
3
+ size 66957746
models/ESRGAN/ESRGAN_4x.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:65fece06e1ccb48853242aa972bdf00ad07a7dd8938d2dcbdf4221b59f6372ce
3
+ size 66929193
models/Stable-diffusion/Put Stable Diffusion checkpoints here.txt ADDED
File without changes
models/Stable-diffusion/moxieDiffusionXL_v16.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0fe2e39405369d15d576f0f8bf1405e53899613711f867c528d2a0d57fefba48
3
+ size 6938051578
models/VAE-approx/model.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4f88c9078bb2238cdd0d8864671dd33e3f42e091e41f08903f3c15e4a54a9b39
3
+ size 213777
models/VAE-approx/vaeapprox-sdxl.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6c8db511f910184436a613807ce06a729f4cf96bbf7977c7c6c40d5b3e4a8333
3
+ size 213777
models/VAE/Put VAE here.txt ADDED
File without changes
models/VAE/sdxl_vae.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:63aeecb90ff7bc1c115395962d3e803571385b61938377bc7089b36e81e92e2e
3
+ size 334641164
models/deepbooru/Put your deepbooru release project folder here.txt ADDED
File without changes
models/diffusers/version_diffusers_cache.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ 1
models/insightface/models/antelopev2/1k3d68.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:df5c06b8a0c12e422b2ed8947b8869faa4105387f199c477af038aa01f9a45cc
3
+ size 143607619
models/insightface/models/antelopev2/2d106det.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f001b856447c413801ef5c42091ed0cd516fcd21f2d6b79635b1e733a7109dbf
3
+ size 5030888
models/insightface/models/antelopev2/genderage.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4fde69b1c810857b88c64a335084f1c3fe8f01246c9a191b48c7bb756d6652fb
3
+ size 1322532
models/insightface/models/antelopev2/glintr100.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4ab1d6435d639628a6f3e5008dd4f929edf4c4124b1a7169e1048f9fef534cdf
3
+ size 260665334
models/insightface/models/antelopev2/scrfd_10g_bnkps.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5838f7fe053675b1c7a08b633df49e7af5495cee0493c7dcf6697200b85b5b91
3
+ size 16923827
models/karlo/ViT-L-14_stats.th ADDED
Binary file (7.08 kB). View file
 
models/svd/put svd here.txt ADDED
File without changes
models/z123/put zero123 here.txt ADDED
File without changes