Skip to content

Commit 263b323

Browse files
authored
Merge branch 'AUTOMATIC1111:master' into draft
2 parents d20dbe4 + 828438b commit 263b323

34 files changed

+1146
-387
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web
7070
- separate prompts using uppercase `AND`
7171
- also supports weights for prompts: `a cat :1.2 AND a dog AND a penguin :2.2`
7272
- No token limit for prompts (original stable diffusion lets you use up to 75 tokens)
73-
- DeepDanbooru integration, creates danbooru style tags for anime prompts (add --deepdanbooru to commandline args)
73+
- DeepDanbooru integration, creates danbooru style tags for anime prompts
7474
- [xformers](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Xformers), major speed increase for select cards: (add --xformers to commandline args)
7575
- via extension: [History tab](https://github.com/yfszzx/stable-diffusion-webui-images-browser): view, direct and delete images conveniently within the UI
7676
- Generate forever option

launch.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,14 +134,13 @@ def prepare_enviroment():
134134

135135
gfpgan_package = os.environ.get('GFPGAN_PACKAGE', "git+https://github.com/TencentARC/GFPGAN.git@8d2447a2d918f8eba5a4a01463fd48e45126a379")
136136
clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLIP.git@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1")
137-
deepdanbooru_package = os.environ.get('DEEPDANBOORU_PACKAGE', "git+https://github.com/KichangKim/DeepDanbooru.git@d91a2963bf87c6a770d74894667e9ffa9f6de7ff")
138137

139138
xformers_windows_package = os.environ.get('XFORMERS_WINDOWS_PACKAGE', 'https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/f/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl')
140139

141140
stable_diffusion_repo = os.environ.get('STABLE_DIFFUSION_REPO', "https://github.com/CompVis/stable-diffusion.git")
142-
taming_transformers_repo = os.environ.get('TAMING_REANSFORMERS_REPO', "https://github.com/CompVis/taming-transformers.git")
141+
taming_transformers_repo = os.environ.get('TAMING_TRANSFORMERS_REPO', "https://github.com/CompVis/taming-transformers.git")
143142
k_diffusion_repo = os.environ.get('K_DIFFUSION_REPO', 'https://github.com/crowsonkb/k-diffusion.git')
144-
codeformer_repo = os.environ.get('CODEFORMET_REPO', 'https://github.com/sczhou/CodeFormer.git')
143+
codeformer_repo = os.environ.get('CODEFORMER_REPO', 'https://github.com/sczhou/CodeFormer.git')
145144
blip_repo = os.environ.get('BLIP_REPO', 'https://github.com/salesforce/BLIP.git')
146145

147146
stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "69ae4b35e0a0f6ee1af8bb9a5d0016ccb27e36dc")
@@ -158,7 +157,6 @@ def prepare_enviroment():
158157
sys.argv, update_check = extract_arg(sys.argv, '--update-check')
159158
sys.argv, run_tests = extract_arg(sys.argv, '--tests')
160159
xformers = '--xformers' in sys.argv
161-
deepdanbooru = '--deepdanbooru' in sys.argv
162160
ngrok = '--ngrok' in sys.argv
163161

164162
try:
@@ -193,9 +191,6 @@ def prepare_enviroment():
193191
elif platform.system() == "Linux":
194192
run_pip("install xformers", "xformers")
195193

196-
if not is_installed("deepdanbooru") and deepdanbooru:
197-
run_pip(f"install {deepdanbooru_package}#egg=deepdanbooru[tensorflow] tensorflow==2.10.0 tensorflow-io==0.27.0", "deepdanbooru")
198-
199194
if not is_installed("pyngrok") and ngrok:
200195
run_pip("install pyngrok", "ngrok")
201196

modules/api/api.py

Lines changed: 58 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,32 @@
55
from threading import Lock
66
from gradio.processing_utils import encode_pil_to_base64, decode_base64_to_file, decode_base64_to_image
77
from fastapi import APIRouter, Depends, FastAPI, HTTPException
8+
from fastapi.security import HTTPBasic, HTTPBasicCredentials
9+
from secrets import compare_digest
10+
811
import modules.shared as shared
12+
from modules import sd_samplers, deepbooru
913
from modules.api.models import *
1014
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images
11-
from modules.sd_samplers import all_samplers
1215
from modules.extras import run_extras, run_pnginfo
1316
from PIL import PngImagePlugin
1417
from modules.sd_models import checkpoints_list
1518
from modules.realesrgan_model import get_realesrgan_models
1619
from typing import List
1720

18-
if shared.cmd_opts.deepdanbooru:
19-
from modules.deepbooru import get_deepbooru_tags
20-
2121
def upscaler_to_index(name: str):
2222
try:
2323
return [x.name.lower() for x in shared.sd_upscalers].index(name.lower())
2424
except:
2525
raise HTTPException(status_code=400, detail=f"Invalid upscaler, needs to be on of these: {' , '.join([x.name for x in sd_upscalers])}")
2626

2727

28-
sampler_to_index = lambda name: next(filter(lambda row: name.lower() == row[1].name.lower(), enumerate(all_samplers)), None)
28+
def validate_sampler_name(name):
29+
config = sd_samplers.all_samplers_map.get(name, None)
30+
if config is None:
31+
raise HTTPException(status_code=404, detail="Sampler not found")
2932

33+
return name
3034

3135
def setUpscalers(req: dict):
3236
reqDict = vars(req)
@@ -57,39 +61,53 @@ def encode_pil_to_base64(image):
5761

5862
class Api:
5963
def __init__(self, app: FastAPI, queue_lock: Lock):
64+
if shared.cmd_opts.api_auth:
65+
self.credenticals = dict()
66+
for auth in shared.cmd_opts.api_auth.split(","):
67+
user, password = auth.split(":")
68+
self.credenticals[user] = password
69+
6070
self.router = APIRouter()
6171
self.app = app
6272
self.queue_lock = queue_lock
63-
self.app.add_api_route("/sdapi/v1/txt2img", self.text2imgapi, methods=["POST"], response_model=TextToImageResponse)
64-
self.app.add_api_route("/sdapi/v1/img2img", self.img2imgapi, methods=["POST"], response_model=ImageToImageResponse)
65-
self.app.add_api_route("/sdapi/v1/extra-single-image", self.extras_single_image_api, methods=["POST"], response_model=ExtrasSingleImageResponse)
66-
self.app.add_api_route("/sdapi/v1/extra-batch-images", self.extras_batch_images_api, methods=["POST"], response_model=ExtrasBatchImagesResponse)
67-
self.app.add_api_route("/sdapi/v1/png-info", self.pnginfoapi, methods=["POST"], response_model=PNGInfoResponse)
68-
self.app.add_api_route("/sdapi/v1/progress", self.progressapi, methods=["GET"], response_model=ProgressResponse)
69-
self.app.add_api_route("/sdapi/v1/interrogate", self.interrogateapi, methods=["POST"])
70-
self.app.add_api_route("/sdapi/v1/interrupt", self.interruptapi, methods=["POST"])
71-
self.app.add_api_route("/sdapi/v1/options", self.get_config, methods=["GET"], response_model=OptionsModel)
72-
self.app.add_api_route("/sdapi/v1/options", self.set_config, methods=["POST"])
73-
self.app.add_api_route("/sdapi/v1/cmd-flags", self.get_cmd_flags, methods=["GET"], response_model=FlagsModel)
74-
self.app.add_api_route("/sdapi/v1/samplers", self.get_samplers, methods=["GET"], response_model=List[SamplerItem])
75-
self.app.add_api_route("/sdapi/v1/upscalers", self.get_upscalers, methods=["GET"], response_model=List[UpscalerItem])
76-
self.app.add_api_route("/sdapi/v1/sd-models", self.get_sd_models, methods=["GET"], response_model=List[SDModelItem])
77-
self.app.add_api_route("/sdapi/v1/hypernetworks", self.get_hypernetworks, methods=["GET"], response_model=List[HypernetworkItem])
78-
self.app.add_api_route("/sdapi/v1/face-restorers", self.get_face_restorers, methods=["GET"], response_model=List[FaceRestorerItem])
79-
self.app.add_api_route("/sdapi/v1/realesrgan-models", self.get_realesrgan_models, methods=["GET"], response_model=List[RealesrganItem])
80-
self.app.add_api_route("/sdapi/v1/prompt-styles", self.get_promp_styles, methods=["GET"], response_model=List[PromptStyleItem])
81-
self.app.add_api_route("/sdapi/v1/artist-categories", self.get_artists_categories, methods=["GET"], response_model=List[str])
82-
self.app.add_api_route("/sdapi/v1/artists", self.get_artists, methods=["GET"], response_model=List[ArtistItem])
73+
self.add_api_route("/sdapi/v1/txt2img", self.text2imgapi, methods=["POST"], response_model=TextToImageResponse)
74+
self.add_api_route("/sdapi/v1/img2img", self.img2imgapi, methods=["POST"], response_model=ImageToImageResponse)
75+
self.add_api_route("/sdapi/v1/extra-single-image", self.extras_single_image_api, methods=["POST"], response_model=ExtrasSingleImageResponse)
76+
self.add_api_route("/sdapi/v1/extra-batch-images", self.extras_batch_images_api, methods=["POST"], response_model=ExtrasBatchImagesResponse)
77+
self.add_api_route("/sdapi/v1/png-info", self.pnginfoapi, methods=["POST"], response_model=PNGInfoResponse)
78+
self.add_api_route("/sdapi/v1/progress", self.progressapi, methods=["GET"], response_model=ProgressResponse)
79+
self.add_api_route("/sdapi/v1/interrogate", self.interrogateapi, methods=["POST"])
80+
self.add_api_route("/sdapi/v1/interrupt", self.interruptapi, methods=["POST"])
81+
self.add_api_route("/sdapi/v1/skip", self.skip, methods=["POST"])
82+
self.add_api_route("/sdapi/v1/options", self.get_config, methods=["GET"], response_model=OptionsModel)
83+
self.add_api_route("/sdapi/v1/options", self.set_config, methods=["POST"])
84+
self.add_api_route("/sdapi/v1/cmd-flags", self.get_cmd_flags, methods=["GET"], response_model=FlagsModel)
85+
self.add_api_route("/sdapi/v1/samplers", self.get_samplers, methods=["GET"], response_model=List[SamplerItem])
86+
self.add_api_route("/sdapi/v1/upscalers", self.get_upscalers, methods=["GET"], response_model=List[UpscalerItem])
87+
self.add_api_route("/sdapi/v1/sd-models", self.get_sd_models, methods=["GET"], response_model=List[SDModelItem])
88+
self.add_api_route("/sdapi/v1/hypernetworks", self.get_hypernetworks, methods=["GET"], response_model=List[HypernetworkItem])
89+
self.add_api_route("/sdapi/v1/face-restorers", self.get_face_restorers, methods=["GET"], response_model=List[FaceRestorerItem])
90+
self.add_api_route("/sdapi/v1/realesrgan-models", self.get_realesrgan_models, methods=["GET"], response_model=List[RealesrganItem])
91+
self.add_api_route("/sdapi/v1/prompt-styles", self.get_promp_styles, methods=["GET"], response_model=List[PromptStyleItem])
92+
self.add_api_route("/sdapi/v1/artist-categories", self.get_artists_categories, methods=["GET"], response_model=List[str])
93+
self.add_api_route("/sdapi/v1/artists", self.get_artists, methods=["GET"], response_model=List[ArtistItem])
94+
95+
def add_api_route(self, path: str, endpoint, **kwargs):
96+
if shared.cmd_opts.api_auth:
97+
return self.app.add_api_route(path, endpoint, dependencies=[Depends(self.auth)], **kwargs)
98+
return self.app.add_api_route(path, endpoint, **kwargs)
99+
100+
def auth(self, credenticals: HTTPBasicCredentials = Depends(HTTPBasic())):
101+
if credenticals.username in self.credenticals:
102+
if compare_digest(credenticals.password, self.credenticals[credenticals.username]):
103+
return True
104+
105+
raise HTTPException(status_code=401, detail="Incorrect username or password", headers={"WWW-Authenticate": "Basic"})
83106

84107
def text2imgapi(self, txt2imgreq: StableDiffusionTxt2ImgProcessingAPI):
85-
sampler_index = sampler_to_index(txt2imgreq.sampler_index)
86-
87-
if sampler_index is None:
88-
raise HTTPException(status_code=404, detail="Sampler not found")
89-
90108
populate = txt2imgreq.copy(update={ # Override __init__ params
91109
"sd_model": shared.sd_model,
92-
"sampler_index": sampler_index[0],
110+
"sampler_name": validate_sampler_name(txt2imgreq.sampler_index),
93111
"do_not_save_samples": True,
94112
"do_not_save_grid": True
95113
}
@@ -109,12 +127,6 @@ def text2imgapi(self, txt2imgreq: StableDiffusionTxt2ImgProcessingAPI):
109127
return TextToImageResponse(images=b64images, parameters=vars(txt2imgreq), info=processed.js())
110128

111129
def img2imgapi(self, img2imgreq: StableDiffusionImg2ImgProcessingAPI):
112-
sampler_index = sampler_to_index(img2imgreq.sampler_index)
113-
114-
if sampler_index is None:
115-
raise HTTPException(status_code=404, detail="Sampler not found")
116-
117-
118130
init_images = img2imgreq.init_images
119131
if init_images is None:
120132
raise HTTPException(status_code=404, detail="Init image not found")
@@ -123,10 +135,9 @@ def img2imgapi(self, img2imgreq: StableDiffusionImg2ImgProcessingAPI):
123135
if mask:
124136
mask = decode_base64_to_image(mask)
125137

126-
127138
populate = img2imgreq.copy(update={ # Override __init__ params
128139
"sd_model": shared.sd_model,
129-
"sampler_index": sampler_index[0],
140+
"sampler_name": validate_sampler_name(img2imgreq.sampler_index),
130141
"do_not_save_samples": True,
131142
"do_not_save_grid": True,
132143
"mask": mask
@@ -231,10 +242,7 @@ def interrogateapi(self, interrogatereq: InterrogateRequest):
231242
if interrogatereq.model == "clip":
232243
processed = shared.interrogator.interrogate(img)
233244
elif interrogatereq.model == "deepdanbooru":
234-
if shared.cmd_opts.deepdanbooru:
235-
processed = get_deepbooru_tags(img)
236-
else:
237-
raise HTTPException(status_code=404, detail="Model not found. Add --deepdanbooru when launching for using the model.")
245+
processed = deepbooru.model.tag(img)
238246
else:
239247
raise HTTPException(status_code=404, detail="Model not found")
240248

@@ -245,6 +253,9 @@ def interruptapi(self):
245253

246254
return {}
247255

256+
def skip(self):
257+
shared.state.skip()
258+
248259
def get_config(self):
249260
options = {}
250261
for key in shared.opts.data.keys():
@@ -256,14 +267,9 @@ def get_config(self):
256267

257268
return options
258269

259-
def set_config(self, req: OptionsModel):
260-
# currently req has all options fields even if you send a dict like { "send_seed": false }, which means it will
261-
# overwrite all options with default values.
262-
raise RuntimeError('Setting options via API is not supported')
263-
264-
reqDict = vars(req)
265-
for o in reqDict:
266-
setattr(shared.opts, o, reqDict[o])
270+
def set_config(self, req: Dict[str, Any]):
271+
for k, v in req.items():
272+
shared.opts.set(k, v)
267273

268274
shared.opts.save(shared.config_filename)
269275
return
@@ -272,7 +278,7 @@ def get_cmd_flags(self):
272278
return vars(shared.cmd_opts)
273279

274280
def get_samplers(self):
275-
return [{"name":sampler[0], "aliases":sampler[2], "options":sampler[3]} for sampler in all_samplers]
281+
return [{"name": sampler[0], "aliases":sampler[2], "options":sampler[3]} for sampler in sd_samplers.all_samplers]
276282

277283
def get_upscalers(self):
278284
upscalers = []

modules/api/models.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,9 @@ class InterrogateResponse(BaseModel):
176176
caption: str = Field(default=None, title="Caption", description="The generated caption for the image.")
177177

178178
fields = {}
179-
for key, value in opts.data.items():
180-
metadata = opts.data_labels.get(key)
181-
optType = opts.typemap.get(type(value), type(value))
179+
for key, metadata in opts.data_labels.items():
180+
value = opts.data.get(key)
181+
optType = opts.typemap.get(type(metadata.default), type(value))
182182

183183
if (metadata is not None):
184184
fields.update({key: (Optional[optType], Field(

0 commit comments

Comments
 (0)