mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 01:04:32 +02:00
refactor api auth
This commit is contained in:
@@ -59,11 +59,19 @@ Tech that can be integrated as part of the core workflow...
|
||||
### Pending Code Updates
|
||||
|
||||
- tested with **torch 2.1** and **cuda 12.1**
|
||||
(production remains on torch2.0.1+cuda11.8)
|
||||
(production remains on torch2.0.1+cuda11.8)
|
||||
- fully extend support of `--data-dir`
|
||||
allows multiple installations to share pretty much everything, not just models
|
||||
- add dark/light theme mode toggle
|
||||
- redo some `clip-skip` functionality
|
||||
- better matching for vae vs model
|
||||
- update to `xyz grid` to allow creation of large number of images without
|
||||
- fixes...amazing how many issues were introduced by porting new a1111 code without adding almost no new functionality
|
||||
allows multiple installations to share pretty much everything, not just models
|
||||
- redo api authentication
|
||||
now api authentication will use same user/pwd (if specified) for ui and strictly enforce it using httpbasicauth
|
||||
new authentication is also fully supported in combination with ssl for both sync and async calls
|
||||
if you want to use api programatically, see examples in `cli/sdapi.py`
|
||||
- add dark/light theme mode toggle
|
||||
- redo some `clip-skip` functionality
|
||||
- better matching for vae vs model
|
||||
- update to `xyz grid` to allow creation of large number of images without
|
||||
- update `gradio` (again)
|
||||
- more prompt parser optimizations
|
||||
- better error handling when importing image settings which are not compatible with current install
|
||||
for example, when upscaler or sampler originally used is not available
|
||||
- fixes...amazing how many issues were introduced by porting new a1111 code without adding almost no new functionality
|
||||
|
||||
@@ -23,7 +23,7 @@ console = Console(log_time=True, log_time_format='%H:%M:%S-%f')
|
||||
pretty_install(console=console)
|
||||
traceback_install(console=console, extra_lines=1, width=console.width, word_wrap=False, indent_guides=False)
|
||||
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'modules', 'lora'))
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'modules', 'lora'))
|
||||
import library.model_util as model_util
|
||||
import library.train_util as train_util
|
||||
|
||||
+47
-7
@@ -5,19 +5,55 @@ helper methods that creates HTTP session with managed connection pool
|
||||
provides async HTTP get/post methods and several helper methods
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import ssl
|
||||
import asyncio
|
||||
import logging
|
||||
import aiohttp
|
||||
import requests
|
||||
import urllib3
|
||||
from util import Map, log
|
||||
|
||||
|
||||
sd_url = "http://127.0.0.1:7860" # automatic1111 api url root
|
||||
sd_url = os.environ.get('SDAPI_URL', "http://127.0.0.1:7860") # automatic1111 api url root
|
||||
|
||||
use_session = True
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
ssl.create_default_context = ssl._create_unverified_context # pylint: disable=protected-access
|
||||
timeout = aiohttp.ClientTimeout(total = None, sock_connect = 10, sock_read = None) # default value is 5 minutes, we need longer for training
|
||||
sess = None
|
||||
quiet = False
|
||||
BaseThreadPolicy = asyncio.WindowsSelectorEventLoopPolicy if sys.platform == "win32" and hasattr(asyncio, "WindowsSelectorEventLoopPolicy") else asyncio.DefaultEventLoopPolicy
|
||||
|
||||
|
||||
class AnyThreadEventLoopPolicy(BaseThreadPolicy):
|
||||
def get_event_loop(self) -> asyncio.AbstractEventLoop:
|
||||
try:
|
||||
return super().get_event_loop()
|
||||
except (RuntimeError, AssertionError):
|
||||
loop = self.new_event_loop()
|
||||
self.set_event_loop(loop)
|
||||
return loop
|
||||
|
||||
asyncio.set_event_loop_policy(AnyThreadEventLoopPolicy())
|
||||
|
||||
|
||||
def authsync():
|
||||
sd_username = os.environ.get('SDAPI_USR', None)
|
||||
sd_password = os.environ.get('SDAPI_PWD', None)
|
||||
if sd_username is not None and sd_password is not None:
|
||||
return requests.auth.HTTPBasicAuth(sd_username, sd_password)
|
||||
return None
|
||||
|
||||
|
||||
def auth():
|
||||
sd_username = os.environ.get('SDAPI_USR', None)
|
||||
sd_password = os.environ.get('SDAPI_PWD', None)
|
||||
if sd_username is not None and sd_password is not None:
|
||||
return aiohttp.BasicAuth(sd_username, sd_password)
|
||||
return None
|
||||
|
||||
|
||||
|
||||
async def result(req):
|
||||
@@ -60,7 +96,7 @@ async def get(endpoint: str, json: dict = None):
|
||||
global sess # pylint: disable=global-statement
|
||||
sess = sess if sess is not None else await session()
|
||||
try:
|
||||
async with sess.get(url = endpoint, json = json) as req:
|
||||
async with sess.get(url=endpoint, json=json, verify_ssl=False) as req:
|
||||
res = await result(req)
|
||||
return res
|
||||
except Exception as err:
|
||||
@@ -70,7 +106,7 @@ async def get(endpoint: str, json: dict = None):
|
||||
|
||||
def getsync(endpoint: str, json: dict = None):
|
||||
try:
|
||||
req = requests.get(f'{sd_url}{endpoint}', json = json) # pylint: disable=missing-timeout
|
||||
req = requests.get(f'{sd_url}{endpoint}', json=json, verify=False, auth=authsync()) # pylint: disable=missing-timeout
|
||||
res = resultsync(req)
|
||||
return res
|
||||
except Exception as err:
|
||||
@@ -85,7 +121,7 @@ async def post(endpoint: str, json: dict = None):
|
||||
await sess.close()
|
||||
sess = await session()
|
||||
try:
|
||||
async with sess.post(url = endpoint, json = json) as req:
|
||||
async with sess.post(url=endpoint, json=json, verify_ssl=False) as req:
|
||||
res = await result(req)
|
||||
return res
|
||||
except Exception as err:
|
||||
@@ -94,7 +130,7 @@ async def post(endpoint: str, json: dict = None):
|
||||
|
||||
|
||||
def postsync(endpoint: str, json: dict = None):
|
||||
req = requests.post(f'{sd_url}{endpoint}', json = json) # pylint: disable=missing-timeout
|
||||
req = requests.post(f'{sd_url}{endpoint}', json=json, verify=False, auth=authsync()) # pylint: disable=missing-timeout
|
||||
res = resultsync(req)
|
||||
return res
|
||||
|
||||
@@ -150,7 +186,7 @@ def shutdown():
|
||||
async def session():
|
||||
global sess # pylint: disable=global-statement
|
||||
time = aiohttp.ClientTimeout(total = None, sock_connect = 10, sock_read = None) # default value is 5 minutes, we need longer for training
|
||||
sess = aiohttp.ClientSession(timeout = time, base_url = sd_url)
|
||||
sess = aiohttp.ClientSession(timeout = time, base_url = sd_url, auth=auth())
|
||||
log.debug({ 'sdapi': 'session created', 'endpoint': sd_url })
|
||||
"""
|
||||
sess = await aiohttp.ClientSession(timeout = timeout).__aenter__()
|
||||
@@ -170,6 +206,7 @@ async def session():
|
||||
async def close():
|
||||
if sess is not None:
|
||||
await asyncio.sleep(0)
|
||||
await sess.close()
|
||||
await sess.__aexit__(None, None, None)
|
||||
log.debug({ 'sdapi': 'session closed', 'endpoint': sd_url })
|
||||
|
||||
@@ -180,6 +217,8 @@ if __name__ == "__main__":
|
||||
asyncio.run(interrupt())
|
||||
if 'progress' in sys.argv:
|
||||
asyncio.run(progress())
|
||||
if 'progresssync' in sys.argv:
|
||||
progresssync()
|
||||
if 'options' in sys.argv:
|
||||
opt = options()
|
||||
log.debug({ 'options' })
|
||||
@@ -189,4 +228,5 @@ if __name__ == "__main__":
|
||||
print(json.dumps(opt['flags'], indent = 2))
|
||||
if 'shutdown' in sys.argv:
|
||||
shutdown()
|
||||
asyncio.run(close())
|
||||
asyncio.run(close(), debug=True)
|
||||
asyncio.run(asyncio.sleep(0.5))
|
||||
|
||||
@@ -17,7 +17,6 @@ import warnings
|
||||
warnings.filterwarnings(action="ignore", category=DeprecationWarning)
|
||||
warnings.filterwarnings(action="ignore", category=UserWarning)
|
||||
warnings.filterwarnings(action="ignore", category=FutureWarning)
|
||||
sys.path.append('.')
|
||||
|
||||
# 3rd party imports
|
||||
import filetype
|
||||
@@ -27,9 +26,9 @@ from tqdm.rich import tqdm
|
||||
# local imports
|
||||
import util
|
||||
import sdapi
|
||||
import options
|
||||
import process
|
||||
import latents
|
||||
import options
|
||||
|
||||
|
||||
# globals
|
||||
@@ -79,7 +78,7 @@ def mem_stats():
|
||||
|
||||
def parse_args():
|
||||
global args # pylint: disable=global-statement
|
||||
parser = argparse.ArgumentParser(description = 'Train')
|
||||
parser = argparse.ArgumentParser(description = 'SD.Next Train')
|
||||
|
||||
group_main = parser.add_argument_group('Main')
|
||||
group_main.add_argument('--type', type=str, choices=['embedding', 'ti', 'lora', 'lyco', 'dreambooth', 'hypernetwork'], default=None, required=True, help='training type')
|
||||
@@ -240,9 +239,9 @@ def train_lora():
|
||||
log.info(f'{args.type} options: {options.lora}')
|
||||
# lora imports
|
||||
lora_path = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, 'modules', 'lora'))
|
||||
lycoris_path = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, 'modules', 'lycoris'))
|
||||
sys.path.append(lora_path)
|
||||
if args.type == 'lyco':
|
||||
lycoris_path = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, 'modules', 'lycoris'))
|
||||
sys.path.append(lycoris_path)
|
||||
log.debug('importing lora lib')
|
||||
import train_network
|
||||
@@ -368,7 +367,7 @@ def process_inputs():
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
log.info('train script for stable diffusion')
|
||||
log.info('SD.Next train script')
|
||||
parse_args()
|
||||
setup_logging()
|
||||
prepare_server()
|
||||
@@ -1,109 +0,0 @@
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import requests
|
||||
from util import Map
|
||||
|
||||
|
||||
sd_url = "http://127.0.0.1:7860" # automatic1111 api url root
|
||||
use_session = True
|
||||
timeout = aiohttp.ClientTimeout(total = None, sock_connect = 10, sock_read = None) # default value is 5 minutes, we need longer for training
|
||||
sess = None
|
||||
quiet = False
|
||||
|
||||
|
||||
async def result(req):
|
||||
if req.status != 200:
|
||||
if not use_session and sess is not None:
|
||||
await sess.close()
|
||||
return Map({ 'error': req.status, 'reason': req.reason, 'url': req.url })
|
||||
else:
|
||||
json = await req.json()
|
||||
if type(json) == list:
|
||||
res = json
|
||||
elif json is None:
|
||||
res = {}
|
||||
else:
|
||||
res = Map(json)
|
||||
return res
|
||||
|
||||
|
||||
def resultsync(req: requests.Response):
|
||||
if req.status_code != 200:
|
||||
return Map({ 'error': req.status_code, 'reason': req.reason, 'url': req.url })
|
||||
else:
|
||||
json = req.json()
|
||||
if type(json) == list:
|
||||
res = json
|
||||
elif json is None:
|
||||
res = {}
|
||||
else:
|
||||
res = Map(json)
|
||||
return res
|
||||
|
||||
|
||||
async def get(endpoint: str, json: dict = None):
|
||||
global sess # pylint: disable=global-statement
|
||||
sess = sess if sess is not None else await session()
|
||||
async with sess.get(url = endpoint, json = json) as req:
|
||||
res = await result(req)
|
||||
return res
|
||||
|
||||
|
||||
def getsync(endpoint: str, json: dict = None):
|
||||
req = requests.get(f'{sd_url}{endpoint}', json = json) # pylint: disable=missing-timeout
|
||||
res = resultsync(req)
|
||||
return res
|
||||
|
||||
|
||||
async def post(endpoint: str, json: dict = None):
|
||||
global sess # pylint: disable=global-statement
|
||||
# sess = sess if sess is not None else await session()
|
||||
if sess and not sess.closed:
|
||||
await sess.close()
|
||||
sess = await session()
|
||||
async with sess.post(url = endpoint, json = json) as req:
|
||||
res = await result(req)
|
||||
return res
|
||||
|
||||
|
||||
def postsync(endpoint: str, json: dict = None):
|
||||
req = requests.post(f'{sd_url}{endpoint}', json = json) # pylint: disable=missing-timeout
|
||||
res = resultsync(req)
|
||||
return res
|
||||
|
||||
|
||||
def interrupt():
|
||||
res = getsync('/sdapi/v1/progress?skip_current_image=true')
|
||||
if 'state' in res and res.state.job_count > 0:
|
||||
res = postsync('/sdapi/v1/interrupt')
|
||||
return res
|
||||
else:
|
||||
return { 'interrupt': 'idle' }
|
||||
|
||||
|
||||
def progress():
|
||||
res = getsync('/sdapi/v1/progress?skip_current_image=true')
|
||||
return res
|
||||
|
||||
|
||||
def options():
|
||||
opt = getsync('/sdapi/v1/options')
|
||||
flags = getsync('/sdapi/v1/cmd-flags')
|
||||
return { 'options': opt, 'flags': flags }
|
||||
|
||||
|
||||
def shutdown():
|
||||
postsync('/sdapi/v1/shutdown')
|
||||
|
||||
|
||||
async def session():
|
||||
global sess # pylint: disable=global-statement
|
||||
time = aiohttp.ClientTimeout(total = None, sock_connect = 10, sock_read = None) # default value is 5 minutes, we need longer for training
|
||||
sess = aiohttp.ClientSession(timeout = time, base_url = sd_url)
|
||||
return sess
|
||||
|
||||
|
||||
async def close():
|
||||
if sess is not None:
|
||||
await asyncio.sleep(0)
|
||||
await sess.__aexit__(None, None, None)
|
||||
@@ -1,85 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
import os
|
||||
|
||||
import transformers
|
||||
transformers.logging.set_verbosity_error()
|
||||
|
||||
|
||||
def get_memory():
|
||||
def gb(val: float):
|
||||
return round(val / 1024 / 1024 / 1024, 2)
|
||||
mem = {}
|
||||
try:
|
||||
import psutil
|
||||
process = psutil.Process(os.getpid())
|
||||
res = process.memory_info()
|
||||
ram_total = 100 * res.rss / process.memory_percent()
|
||||
ram = { 'free': gb(ram_total - res.rss), 'used': gb(res.rss), 'total': gb(ram_total) }
|
||||
mem.update({ 'ram': ram })
|
||||
except Exception as e:
|
||||
mem.update({ 'ram': e })
|
||||
try:
|
||||
import torch
|
||||
if torch.cuda.is_available():
|
||||
s = torch.cuda.mem_get_info()
|
||||
gpu = { 'free': gb(s[0]), 'used': gb(s[1] - s[0]), 'total': gb(s[1]) }
|
||||
s = dict(torch.cuda.memory_stats('cuda'))
|
||||
allocated = { 'current': gb(s['allocated_bytes.all.current']), 'peak': gb(s['allocated_bytes.all.peak']) }
|
||||
reserved = { 'current': gb(s['reserved_bytes.all.current']), 'peak': gb(s['reserved_bytes.all.peak']) }
|
||||
active = { 'current': gb(s['active_bytes.all.current']), 'peak': gb(s['active_bytes.all.peak']) }
|
||||
inactive = { 'current': gb(s['inactive_split_bytes.all.current']), 'peak': gb(s['inactive_split_bytes.all.peak']) }
|
||||
warnings = { 'retries': s['num_alloc_retries'], 'oom': s['num_ooms'] }
|
||||
mem.update({
|
||||
'gpu': gpu,
|
||||
'gpu-active': active,
|
||||
'gpu-allocated': allocated,
|
||||
'gpu-reserved': reserved,
|
||||
'gpu-inactive': inactive,
|
||||
'events': warnings,
|
||||
})
|
||||
except:
|
||||
pass
|
||||
return Map(mem)
|
||||
|
||||
|
||||
class Map(dict): # pylint: disable=C0205
|
||||
__slots__ = ('__dict__') # pylint: disable=C0325
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Map, self).__init__(*args, **kwargs)
|
||||
for arg in args:
|
||||
if isinstance(arg, dict):
|
||||
for k, v in arg.items():
|
||||
if isinstance(v, dict):
|
||||
v = Map(v)
|
||||
if isinstance(v, list):
|
||||
self.__convert(v)
|
||||
self[k] = v
|
||||
if kwargs:
|
||||
for k, v in kwargs.items():
|
||||
if isinstance(v, dict):
|
||||
v = Map(v)
|
||||
elif isinstance(v, list):
|
||||
self.__convert(v)
|
||||
self[k] = v
|
||||
def __convert(self, v):
|
||||
for elem in range(0, len(v)): # pylint: disable=consider-using-enumerate
|
||||
if isinstance(v[elem], dict):
|
||||
v[elem] = Map(v[elem])
|
||||
elif isinstance(v[elem], list):
|
||||
self.__convert(v[elem])
|
||||
def __getattr__(self, attr):
|
||||
return self.get(attr)
|
||||
def __setattr__(self, key, value):
|
||||
self.__setitem__(key, value)
|
||||
def __setitem__(self, key, value):
|
||||
super(Map, self).__setitem__(key, value)
|
||||
self.__dict__.update({key: value})
|
||||
def __delattr__(self, item):
|
||||
self.__delitem__(item)
|
||||
def __delitem__(self, key):
|
||||
super(Map, self).__delitem__(key)
|
||||
del self.__dict__[key]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
+6
-2
@@ -6,9 +6,13 @@ generic helper methods
|
||||
import os
|
||||
import string
|
||||
import logging
|
||||
import warnings
|
||||
|
||||
log_format = '%(asctime)s %(levelname)s: %(message)s'
|
||||
logging.basicConfig(level = logging.INFO, format = log_format)
|
||||
warnings.filterwarnings(action="ignore", category=DeprecationWarning)
|
||||
warnings.filterwarnings(action="ignore", category=FutureWarning)
|
||||
warnings.filterwarnings(action="ignore", category=UserWarning)
|
||||
log = logging.getLogger("sd")
|
||||
|
||||
|
||||
@@ -52,14 +56,14 @@ def get_memory():
|
||||
reserved = { 'current': gb(s['reserved_bytes.all.current']), 'peak': gb(s['reserved_bytes.all.peak']) }
|
||||
active = { 'current': gb(s['active_bytes.all.current']), 'peak': gb(s['active_bytes.all.peak']) }
|
||||
inactive = { 'current': gb(s['inactive_split_bytes.all.current']), 'peak': gb(s['inactive_split_bytes.all.peak']) }
|
||||
warnings = { 'retries': s['num_alloc_retries'], 'oom': s['num_ooms'] }
|
||||
events = { 'retries': s['num_alloc_retries'], 'oom': s['num_ooms'] }
|
||||
mem.update({
|
||||
'gpu': gpu,
|
||||
'gpu-active': active,
|
||||
'gpu-allocated': allocated,
|
||||
'gpu-reserved': reserved,
|
||||
'gpu-inactive': inactive,
|
||||
'events': warnings,
|
||||
'events': events,
|
||||
})
|
||||
except:
|
||||
pass
|
||||
|
||||
Submodule extensions-builtin/sd-webui-controlnet updated: 7c674f8364...2514a460ab
Submodule extensions-builtin/sd-webui-model-converter updated: d19e281682...f6e0fa5386
+22
-12
@@ -68,6 +68,8 @@ def setup_logging(clean=False):
|
||||
traceback_install(console=console, extra_lines=1, width=console.width, word_wrap=False, indent_guides=False, suppress=[])
|
||||
rh = RichHandler(show_time=True, omit_repeated_times=False, show_level=True, show_path=False, markup=False, rich_tracebacks=True, log_time_format='%H:%M:%S-%f', level=logging.DEBUG if args.debug else logging.INFO, console=console)
|
||||
rh.set_name(logging.DEBUG if args.debug else logging.INFO)
|
||||
while log.hasHandlers() and len(log.handlers) > 0:
|
||||
log.removeHandler(log.handlers[0])
|
||||
log.addHandler(rh)
|
||||
|
||||
|
||||
@@ -186,6 +188,7 @@ def clone(url, folder, commithash=None):
|
||||
git(f'checkout {commithash}', folder)
|
||||
return
|
||||
else:
|
||||
log.info(f'Cloning repository: {url}')
|
||||
git(f'clone "{url}" "{folder}"')
|
||||
if commithash is not None:
|
||||
git(f'-C "{folder}" checkout {commithash}')
|
||||
@@ -309,7 +312,7 @@ def install_packages():
|
||||
# openclip_package = os.environ.get('OPENCLIP_PACKAGE', "git+https://github.com/mlfoundations/open_clip.git@bb6e834e9c70d9c27d0dc3ecedeebeaeb1ffad6b")
|
||||
# install(gfpgan_package, 'gfpgan')
|
||||
# install(openclip_package, 'open-clip-torch')
|
||||
clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLIP.git@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1")
|
||||
clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLIP.git")
|
||||
install(clip_package, 'clip')
|
||||
install('onnxruntime==1.14.0', 'onnxruntime', ignore=True)
|
||||
|
||||
@@ -321,19 +324,24 @@ def install_repositories():
|
||||
log.info('Installing repositories')
|
||||
os.makedirs(os.path.join(os.path.dirname(__file__), 'repositories'), exist_ok=True)
|
||||
stable_diffusion_repo = os.environ.get('STABLE_DIFFUSION_REPO', "https://github.com/Stability-AI/stablediffusion.git")
|
||||
stable_diffusion_commit = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "cf1d67a6fd5ea1aa600c4df58e5b47da45f6bdbf")
|
||||
# stable_diffusion_commit = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "cf1d67a6fd5ea1aa600c4df58e5b47da45f6bdbf")
|
||||
stable_diffusion_commit = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', None)
|
||||
clone(stable_diffusion_repo, d('stable-diffusion-stability-ai'), stable_diffusion_commit)
|
||||
taming_transformers_repo = os.environ.get('TAMING_TRANSFORMERS_REPO', "https://github.com/CompVis/taming-transformers.git")
|
||||
taming_transformers_commit = os.environ.get('TAMING_TRANSFORMERS_COMMIT_HASH', "3ba01b241669f5ade541ce990f7650a3b8f65318")
|
||||
# taming_transformers_commit = os.environ.get('TAMING_TRANSFORMERS_COMMIT_HASH', "3ba01b241669f5ade541ce990f7650a3b8f65318")
|
||||
taming_transformers_commit = os.environ.get('TAMING_TRANSFORMERS_COMMIT_HASH', None)
|
||||
clone(taming_transformers_repo, d('taming-transformers'), taming_transformers_commit)
|
||||
k_diffusion_repo = os.environ.get('K_DIFFUSION_REPO', 'https://github.com/crowsonkb/k-diffusion.git')
|
||||
k_diffusion_commit = os.environ.get('K_DIFFUSION_COMMIT_HASH', "b43db16749d51055f813255eea2fdf1def801919")
|
||||
# k_diffusion_commit = os.environ.get('K_DIFFUSION_COMMIT_HASH', "b43db16749d51055f813255eea2fdf1def801919")
|
||||
k_diffusion_commit = os.environ.get('K_DIFFUSION_COMMIT_HASH', None)
|
||||
clone(k_diffusion_repo, d('k-diffusion'), k_diffusion_commit)
|
||||
codeformer_repo = os.environ.get('CODEFORMER_REPO', 'https://github.com/sczhou/CodeFormer.git')
|
||||
codeformer_commit = os.environ.get('CODEFORMER_COMMIT_HASH', "c5b4593074ba6214284d6acd5f1719b6c5d739af")
|
||||
# codeformer_commit = os.environ.get('CODEFORMER_COMMIT_HASH', "c5b4593074ba6214284d6acd5f1719b6c5d739af")
|
||||
codeformer_commit = os.environ.get('CODEFORMER_COMMIT_HASH', "7a584fd")
|
||||
clone(codeformer_repo, d('CodeFormer'), codeformer_commit)
|
||||
blip_repo = os.environ.get('BLIP_REPO', 'https://github.com/salesforce/BLIP.git')
|
||||
blip_commit = os.environ.get('BLIP_COMMIT_HASH', "48211a1594f1321b00f14c9f7a5b4813144b2fb9")
|
||||
# blip_commit = os.environ.get('BLIP_COMMIT_HASH', "48211a1594f1321b00f14c9f7a5b4813144b2fb9")
|
||||
blip_commit = os.environ.get('BLIP_COMMIT_HASH', None)
|
||||
clone(blip_repo, d('BLIP'), blip_commit)
|
||||
|
||||
|
||||
@@ -635,12 +643,14 @@ def extensions_preload(force = False):
|
||||
log.info('Running extension preloading')
|
||||
if args.safe:
|
||||
log.info('Running in safe mode without user extensions')
|
||||
from modules.script_loading import preload_extensions
|
||||
from modules.paths_internal import extensions_builtin_dir, extensions_dir
|
||||
extension_folders = [extensions_builtin_dir] if args.safe else [extensions_builtin_dir, extensions_dir]
|
||||
for ext_dir in extension_folders:
|
||||
preload_extensions(ext_dir, parser)
|
||||
|
||||
try:
|
||||
from modules.script_loading import preload_extensions
|
||||
from modules.paths_internal import extensions_builtin_dir, extensions_dir
|
||||
extension_folders = [extensions_builtin_dir] if args.safe else [extensions_builtin_dir, extensions_dir]
|
||||
for ext_dir in extension_folders:
|
||||
preload_extensions(ext_dir, parser, args.debug)
|
||||
except:
|
||||
log.error('Error running extension preloading')
|
||||
|
||||
def git_reset():
|
||||
log.warning('Running GIT reset')
|
||||
|
||||
@@ -9,6 +9,7 @@ commandline_args = os.environ.get('COMMANDLINE_ARGS', "")
|
||||
sys.argv += shlex.split(commandline_args)
|
||||
|
||||
import installer
|
||||
installer.setup_logging(False)
|
||||
installer.add_args()
|
||||
installer.ensure_base_requirements()
|
||||
installer.parse_args()
|
||||
|
||||
+12
-22
@@ -88,25 +88,16 @@ def encode_pil_to_base64(image):
|
||||
|
||||
class Api:
|
||||
def __init__(self, app: FastAPI, queue_lock: Lock):
|
||||
if shared.cmd_opts.api_auth:
|
||||
self.credentials = dict()
|
||||
for auth in shared.cmd_opts.api_auth.split(","):
|
||||
self.credentials = dict()
|
||||
if shared.cmd_opts.auth:
|
||||
for auth in shared.cmd_opts.auth.split(","):
|
||||
user, password = auth.split(":")
|
||||
self.credentials[user] = password
|
||||
else:
|
||||
if shared.cmd_opts.auth:
|
||||
self.credentials = dict()
|
||||
for auth in shared.cmd_opts.auth.split(","):
|
||||
user, password = auth.split(":")
|
||||
self.credentials[user] = password
|
||||
user, password = [x.strip() for x in shared.cmd_opts.auth.strip('"').replace('\n', '').split(',') if x.strip()].split(':')
|
||||
self.credentials[user] = password
|
||||
if shared.cmd_opts.authfile:
|
||||
self.credentials = dict()
|
||||
with open(shared.cmd_opts.authfile, 'r', encoding="utf8") as file:
|
||||
for line in file.readlines():
|
||||
user, password = line.split(":")
|
||||
self.credentials[user] = password
|
||||
self.credentials[user.replace('"', '').strip()] = password.replace('"', '').strip()
|
||||
if shared.cmd_opts.auth_file:
|
||||
with open(shared.cmd_opts.auth_file, 'r', encoding="utf8") as file:
|
||||
for line in file.readlines():
|
||||
user, password = line.split(":")
|
||||
self.credentials[user.replace('"', '').strip()] = password.replace('"', '').strip()
|
||||
|
||||
self.router = APIRouter()
|
||||
self.app = app
|
||||
@@ -146,7 +137,7 @@ class Api:
|
||||
self.default_script_arg_img2img = []
|
||||
|
||||
def add_api_route(self, path: str, endpoint, **kwargs):
|
||||
if shared.cmd_opts.api_auth:
|
||||
if shared.cmd_opts.auth or shared.cmd_opts.auth_file:
|
||||
return self.app.add_api_route(path, endpoint, dependencies=[Depends(self.auth)], **kwargs)
|
||||
return self.app.add_api_route(path, endpoint, **kwargs)
|
||||
|
||||
@@ -154,7 +145,7 @@ class Api:
|
||||
if credentials.username in self.credentials:
|
||||
if compare_digest(credentials.password, self.credentials[credentials.username]):
|
||||
return True
|
||||
raise HTTPException(status_code=401, detail="Incorrect username or password", headers={"WWW-Authenticate": "Basic"})
|
||||
raise HTTPException(status_code=401, detail="Unauthorized", headers={"WWW-Authenticate": "Basic"})
|
||||
|
||||
def get_selectable_script(self, script_name, script_runner):
|
||||
if script_name is None or script_name == "":
|
||||
@@ -630,6 +621,5 @@ class Api:
|
||||
|
||||
def launch(self, server_name, port):
|
||||
self.app.include_router(self.router)
|
||||
server_name = "0.0.0.0" if cmd_opts.listen else None
|
||||
|
||||
server_name = "0.0.0.0" if shared.cmd_opts.listen else None
|
||||
uvicorn.run(self.app, host=server_name, port=port)
|
||||
|
||||
+2
-2
@@ -23,10 +23,9 @@ group.add_argument("--listen", action='store_true', help="Launch web server usin
|
||||
group.add_argument("--port", type=int, default=7860, help="Launch web server with given server port, default: %(default)s")
|
||||
group.add_argument("--freeze", action='store_true', help="Disable editing settings", default=False)
|
||||
group.add_argument("--auth", type=str, help='Set access authentication like "user:pwd,user:pwd""', default=None)
|
||||
group.add_argument("--authfile", type=str, help='Set access authentication using file, default: %(default)s', default=None)
|
||||
group.add_argument("--auth-file", type=str, help='Set access authentication using file, default: %(default)s', default=None)
|
||||
group.add_argument("--autolaunch", action='store_true', help="Open the UI URL in the system's default browser upon launch", default=False)
|
||||
group.add_argument('--api-only', default = False, action='store_true', help = "Run in API only mode without starting UI")
|
||||
group.add_argument("--api-auth", type=str, help='Set API authentication, default: %(default)s', default=None)
|
||||
group.add_argument("--api-log", default=False, action='store_true', help="Enable logging of all API requests, default: %(default)s")
|
||||
group.add_argument("--device-id", type=str, help="Select the default CUDA device to use, default: %(default)s", default=None)
|
||||
group.add_argument("--cors-origins", type=str, help="Allowed CORS origins as comma-separated list, default: %(default)s", default=None)
|
||||
@@ -57,6 +56,7 @@ group.add_argument("--disable-safe-unpickle", action='store_true', help=argparse
|
||||
group.add_argument("--lowram", action='store_true', help=argparse.SUPPRESS)
|
||||
group.add_argument("--disable-extension-access", default = False, action='store_true', help=argparse.SUPPRESS)
|
||||
group.add_argument("--api", help=argparse.SUPPRESS, default=True)
|
||||
group.add_argument("--api-auth", type=str, help=argparse.SUPPRESS, default=None)
|
||||
|
||||
|
||||
def compatibility_args(opts, args):
|
||||
|
||||
@@ -20,10 +20,8 @@ codeformer = None
|
||||
|
||||
|
||||
def setup_model(dirname):
|
||||
global model_path
|
||||
if not os.path.exists(model_path):
|
||||
os.makedirs(model_path)
|
||||
|
||||
path = modules.paths.paths.get("CodeFormer", None)
|
||||
if path is None:
|
||||
return
|
||||
@@ -31,7 +29,7 @@ def setup_model(dirname):
|
||||
try:
|
||||
from torchvision.transforms.functional import normalize
|
||||
from modules.codeformer.codeformer_arch import CodeFormer
|
||||
from basicsr.utils import imwrite, img2tensor, tensor2img
|
||||
from basicsr.utils import img2tensor, tensor2img
|
||||
from facelib.utils.face_restoration_helper import FaceRestoreHelper
|
||||
from facelib.detection.retinaface import retinaface
|
||||
from modules.shared import cmd_opts
|
||||
@@ -74,7 +72,7 @@ def setup_model(dirname):
|
||||
|
||||
def send_model_to(self, device):
|
||||
self.net.to(device)
|
||||
self.face_helper.face_det.to(device)
|
||||
self.face_helper.face_det.to(device) # pylint: disable=no-member
|
||||
self.face_helper.face_parse.to(device)
|
||||
|
||||
def restore(self, np_image, w=None):
|
||||
@@ -93,7 +91,7 @@ def setup_model(dirname):
|
||||
self.face_helper.get_face_landmarks_5(only_center_face=False, resize=640, eye_dist_threshold=5)
|
||||
self.face_helper.align_warp_face()
|
||||
|
||||
for idx, cropped_face in enumerate(self.face_helper.cropped_faces):
|
||||
for _idx, cropped_face in enumerate(self.face_helper.cropped_faces):
|
||||
cropped_face_t = img2tensor(cropped_face / 255., bgr2rgb=True, float32=True)
|
||||
normalize(cropped_face_t, (0.5, 0.5, 0.5), (0.5, 0.5, 0.5), inplace=True)
|
||||
cropped_face_t = cropped_face_t.unsqueeze(0).to(devices.device_codeformer)
|
||||
@@ -129,10 +127,10 @@ def setup_model(dirname):
|
||||
|
||||
return restored_img
|
||||
|
||||
global have_codeformer
|
||||
global have_codeformer # pylint: disable=global-statement
|
||||
have_codeformer = True
|
||||
|
||||
global codeformer
|
||||
global codeformer # pylint: disable=global-statement
|
||||
codeformer = FaceRestorerCodeFormer(dirname)
|
||||
shared.face_restorers.append(codeformer)
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 965400086, Size: 512x512, Model
|
||||
res["Prompt"] = prompt
|
||||
res["Negative prompt"] = negative_prompt
|
||||
for k, v in re_param.findall(lastline):
|
||||
v = v[1:-1] if v[0] == '"' and v[-1] == '"' else v
|
||||
v = v[1:-1] if len(v) > 0 and v[0] == '"' and v[-1] == '"' else v
|
||||
m = re_imagesize.match(v)
|
||||
if m is not None:
|
||||
res[f"{k}-1"] = m.group(1)
|
||||
|
||||
+1
-1
@@ -236,7 +236,7 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None):
|
||||
upscalers = [x for x in shared.sd_upscalers if x.name == upscaler_name]
|
||||
if len(upscalers) == 0:
|
||||
upscaler = shared.sd_upscalers[0]
|
||||
shared.log.warning(f"could not find upscaler named {upscaler_name or '<empty string>'}, using {upscaler.name} as a fallback")
|
||||
shared.log.warning(f"Could not find upscaler named {upscaler_name or '<empty string>'}, using {upscaler.name} as a fallback")
|
||||
else:
|
||||
upscaler = upscalers[0]
|
||||
im = upscaler.scaler.upscale(im, scale, upscaler.data_path)
|
||||
|
||||
@@ -3,7 +3,6 @@ import math
|
||||
import os
|
||||
import hashlib
|
||||
import random
|
||||
import logging
|
||||
from typing import Any, Dict, List
|
||||
import torch
|
||||
import numpy as np
|
||||
@@ -33,13 +32,13 @@ opt_f = 8
|
||||
|
||||
|
||||
def setup_color_correction(image):
|
||||
logging.info("Calibrating color correction.")
|
||||
log.debug("Calibrating color correction.")
|
||||
correction_target = cv2.cvtColor(np.asarray(image.copy()), cv2.COLOR_RGB2LAB)
|
||||
return correction_target
|
||||
|
||||
|
||||
def apply_color_correction(correction, original_image):
|
||||
logging.info("Applying color correction.")
|
||||
log.debug("Applying color correction.")
|
||||
image = Image.fromarray(cv2.cvtColor(exposure.match_histograms(
|
||||
cv2.cvtColor(np.asarray(original_image), cv2.COLOR_RGB2LAB),
|
||||
correction,
|
||||
@@ -575,7 +574,9 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
for n in range(p.n_iter):
|
||||
p.iteration = n
|
||||
if state.skipped:
|
||||
shared.log.debug(f'Process skipped: {n}/{p.n_iter}')
|
||||
state.skipped = False
|
||||
continue
|
||||
if state.interrupted:
|
||||
shared.log.debug(f'Process interrupted: {n}/{p.n_iter}')
|
||||
break
|
||||
@@ -710,7 +711,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
index_of_first_image=index_of_first_image,
|
||||
infotexts=infotexts,
|
||||
)
|
||||
if p.scripts is not None:
|
||||
if p.scripts is not None and not state.interrupted:
|
||||
p.scripts.postprocess(p, res)
|
||||
return res
|
||||
|
||||
@@ -803,10 +804,12 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
self.sampler = sd_samplers.create_sampler(self.sampler_name, self.sd_model)
|
||||
latent_scale_mode = shared.latent_upscale_modes.get(self.hr_upscaler, None) if self.hr_upscaler is not None else shared.latent_upscale_modes.get(shared.latent_upscale_default_mode, "nearest")
|
||||
if self.enable_hr and latent_scale_mode is None:
|
||||
assert len([x for x in shared.sd_upscalers if x.name == self.hr_upscaler]) > 0, f"could not find upscaler named {self.hr_upscaler}"
|
||||
if len([x for x in shared.sd_upscalers if x.name == self.hr_upscaler]) == 0:
|
||||
log.warning("Could not find upscaler to use with hrfix")
|
||||
self.enable_hr = False
|
||||
x = create_random_tensors([opt_C, self.height // opt_f, self.width // opt_f], seeds=seeds, subseeds=subseeds, subseed_strength=self.subseed_strength, seed_resize_from_h=self.seed_resize_from_h, seed_resize_from_w=self.seed_resize_from_w, p=self)
|
||||
samples = self.sampler.sample(self, x, conditioning, unconditional_conditioning, image_conditioning=self.txt2img_image_conditioning(x))
|
||||
if not self.enable_hr:
|
||||
if not self.enable_hr or state.interrupted or state.skipped:
|
||||
return samples
|
||||
self.is_hr_pass = True
|
||||
target_width = self.hr_upscale_to_x
|
||||
|
||||
@@ -3,18 +3,24 @@ import importlib.util
|
||||
import modules.errors as errors
|
||||
|
||||
|
||||
def load_module(path):
|
||||
preloaded = []
|
||||
|
||||
|
||||
def load_module(path, detailed=False):
|
||||
module_spec = importlib.util.spec_from_file_location(os.path.basename(path), path)
|
||||
module = importlib.util.module_from_spec(module_spec)
|
||||
try:
|
||||
module_spec.loader.exec_module(module)
|
||||
except Exception as e:
|
||||
errors.display(e, f'Module load: {path}')
|
||||
if detailed:
|
||||
errors.display(e, f'Module load: {path}')
|
||||
else:
|
||||
errors.log.error(f'Module load: {path}')
|
||||
return module
|
||||
|
||||
preloaded = []
|
||||
|
||||
def preload_extensions(extensions_dir, parser):
|
||||
|
||||
def preload_extensions(extensions_dir, parser, detailed=False):
|
||||
if not os.path.isdir(extensions_dir):
|
||||
return
|
||||
for dirname in sorted(os.listdir(extensions_dir)):
|
||||
@@ -29,4 +35,7 @@ def preload_extensions(extensions_dir, parser):
|
||||
if hasattr(module, 'preload'):
|
||||
module.preload(parser)
|
||||
except Exception as e:
|
||||
errors.display(e, f'Extension preload: {preload_script}')
|
||||
if detailed:
|
||||
errors.display(e, f'Extension preload: {preload_script}')
|
||||
else:
|
||||
errors.log.error(f'Extension preload: {preload_script}')
|
||||
|
||||
@@ -11,7 +11,7 @@ class ScriptPostprocessingCodeFormer(scripts_postprocessing.ScriptPostprocessing
|
||||
|
||||
def ui(self):
|
||||
with FormRow():
|
||||
codeformer_visibility = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label="CodeFormer visibility", value=1.0, elem_id="extras_codeformer_visibility")
|
||||
codeformer_visibility = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label="CodeFormer visibility", value=0.0, elem_id="extras_codeformer_visibility")
|
||||
codeformer_weight = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label="CodeFormer weight (0 = max), 1 = min)", value=0.2, elem_id="extras_codeformer_weight")
|
||||
|
||||
return {
|
||||
|
||||
@@ -83,16 +83,17 @@ class ScriptPostprocessingUpscale(scripts_postprocessing.ScriptPostprocessing):
|
||||
upscaler_1_name = None
|
||||
|
||||
upscaler1 = next(iter([x for x in shared.sd_upscalers if x.name == upscaler_1_name]), None)
|
||||
assert upscaler1 or (upscaler_1_name is None), f'could not find upscaler named {upscaler_1_name}'
|
||||
|
||||
if not upscaler1:
|
||||
shared.log.warning(f"Could not find upscaler named {upscaler_1_name or '<empty string>'}")
|
||||
return
|
||||
|
||||
if upscaler_2_name == "None":
|
||||
upscaler_2_name = None
|
||||
|
||||
upscaler2 = next(iter([x for x in shared.sd_upscalers if x.name == upscaler_2_name and x.name != "None"]), None)
|
||||
assert upscaler2 or (upscaler_2_name is None), f'could not find upscaler named {upscaler_2_name}'
|
||||
if not upscaler2 and (upscaler_2_name is not None):
|
||||
shared.log.warning(f"Could not find upscaler named {upscaler_1_name or '<empty string>'}")
|
||||
return
|
||||
|
||||
upscaled_image = self.upscale(pp.image, pp.info, upscaler1, upscale_mode, upscale_by, upscale_to_width, upscale_to_height, upscale_crop)
|
||||
pp.info["Postprocess upscaler"] = upscaler1.name
|
||||
@@ -128,7 +129,8 @@ class ScriptPostprocessingUpscaleSimple(ScriptPostprocessingUpscale):
|
||||
return
|
||||
|
||||
upscaler1 = next(iter([x for x in shared.sd_upscalers if x.name == upscaler_name]), None)
|
||||
assert upscaler1, f'could not find upscaler named {upscaler_name}'
|
||||
if upscaler1 is None:
|
||||
shared.log.warning(f"Could not find upscaler named {upscaler_name or '<empty string>'}")
|
||||
|
||||
pp.image = self.upscale(pp.image, pp.info, upscaler1, 0, upscale_by, 0, 0, False)
|
||||
pp.info["Postprocess upscaler"] = upscaler1.name
|
||||
|
||||
@@ -223,8 +223,8 @@ def start_ui():
|
||||
gradio_auth_creds = []
|
||||
if cmd_opts.auth:
|
||||
gradio_auth_creds += [x.strip() for x in cmd_opts.auth.strip('"').replace('\n', '').split(',') if x.strip()]
|
||||
if cmd_opts.authfile:
|
||||
with open(cmd_opts.authfile, 'r', encoding="utf8") as file:
|
||||
if cmd_opts.auth_file:
|
||||
with open(cmd_opts.auth_file, 'r', encoding="utf8") as file:
|
||||
for line in file.readlines():
|
||||
gradio_auth_creds += [x.strip() for x in line.split(',') if x.strip()]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user