diff --git a/TODO.md b/TODO.md index 1c5d89da1..e72f7fcf9 100644 --- a/TODO.md +++ b/TODO.md @@ -11,12 +11,9 @@ N/A Stuff to be added, in no particular order... - Diffusers: - - Add Lyco support - Add ControlNet - - Fix DeepFloyd IF model - Add unCLIP model - Add Training support - - Add long prompts - Technical debt: - Port **A1111** stuff - Port `p.all_hr_prompts` @@ -24,15 +21,11 @@ Stuff to be added, in no particular order... - Non-technical: - Update Wiki - Rename repo: **automatic** -> **sdnext** - - [Localization](https://app.transifex.com/signup/open-source/) - New Minor - Prompt padding for positive/negative - - Add EN provider for VAEs - - Built-in `motd`-style notifications - New Major - Profile manager (for `config.json` and `ui-config.json`) - Multi-user support - - Add [SAG](https://huggingface.co/docs/diffusers/v0.19.3/en/api/pipelines/self_attention_guidance), [SAG](https://github.com/ashen-sensored/sd_webui_SAG) - Image phash and hdash using `imagehash` - Model merge using `git-rebasin` - Enable refiner-style workflow for `ldm` backend @@ -71,6 +64,8 @@ Tech that can be integrated as part of the core workflow... - [QuickEmbedding](https://github.com/ethansmith2000/QuickEmbedding) - [DragGAN](https://github.com/XingangPan/DragGAN) - [LamaCleaner](https://github.com/Sanster/lama-cleaner) +- [SAG](https://huggingface.co/docs/diffusers/v0.19.3/en/api/pipelines/self_attention_guidance), [SAG](https://github.com/ashen-sensored/sd_webui_SAG) +- [Localization](https://app.transifex.com/signup/open-source/) - `TensorRT` ## Random diff --git a/installer.py b/installer.py index cd083dde4..bb7d28431 100644 --- a/installer.py +++ b/installer.py @@ -18,6 +18,7 @@ class Dot(dict): # dot notation access to dictionary attributes __delattr__ = dict.__delitem__ +version = None log = logging.getLogger("sd") log_file = os.path.join(os.path.dirname(__file__), 'sdnext.log') log_rolled = False @@ -177,16 +178,16 @@ def installed(package, friendly: str = None): spec = pkg_resources.working_set.by_key.get(p[0].replace('_', '-'), None) # check name variations ok = ok and spec is not None if ok: - version = pkg_resources.get_distribution(p[0]).version - # log.debug(f"Package version found: {p[0]} {version}") + package_version = pkg_resources.get_distribution(p[0]).version + # log.debug(f"Package version found: {p[0]} {package_version}") if len(p) > 1: - exact = version == p[1] + exact = package_version == p[1] ok = ok and (exact or args.experimental) if not exact: if args.experimental: - log.warning(f"Package allowing experimental: {p[0]} {version} required {p[1]}") + log.warning(f"Package allowing experimental: {p[0]} {package_version} required {p[1]}") else: - log.warning(f"Package wrong version: {p[0]} {version} required {p[1]}") + log.warning(f"Package wrong version: {p[0]} {package_version} required {p[1]}") else: log.debug(f"Package version not found: {p[0]}") return ok @@ -466,8 +467,8 @@ def check_torch(): try: if args.use_directml and allow_directml: import torch_directml # pylint: disable=import-error - version = pkg_resources.get_distribution("torch-directml") - log.info(f'Torch backend: DirectML ({version})') + dml_ver = pkg_resources.get_distribution("torch-directml") + log.info(f'Torch backend: DirectML ({dml_ver})') for i in range(0, torch_directml.device_count()): log.info(f'Torch detected GPU: {torch_directml.device_name(i)}') except Exception: @@ -784,7 +785,7 @@ def check_extensions(): def get_version(): - version = None + global version # pylint: disable=global-statement if version is None: try: res = subprocess.run('git log --pretty=format:"%h %ad" -1 --date=short', stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell=True, check=True) diff --git a/javascript/loader.js b/javascript/loader.js index f32c7d294..9b8ef4b3e 100644 --- a/javascript/loader.js +++ b/javascript/loader.js @@ -31,11 +31,16 @@ async function createSplash() { const splash = `
+
`; document.body.insertAdjacentHTML('beforeend', splash); await preloadImages(); - const imgElement = `
`; - document.getElementById('splash').insertAdjacentHTML('afterbegin', imgElement); + const imgEl = `
`; + document.getElementById('splash').insertAdjacentHTML('afterbegin', imgEl); + fetch('/sdapi/v1/motd') + .then((res) => res.text()) + .then((text) => document.getElementById('motd').innerHTML = text.replace(/["]+/g, '')) + .catch((err) => console.error('getMOTD:', err)); } async function removeSplash() { diff --git a/javascript/style.css b/javascript/style.css index 9d9312db6..bc6188003 100644 --- a/javascript/style.css +++ b/javascript/style.css @@ -253,6 +253,7 @@ div.controlnet_main_options { display: grid; grid-template-columns: 1fr 1fr; gri /* loader */ .splash { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 1000; display: block; text-align: center; } +.motd { margin-top: 2em; color: var(--body-text-color-subdued); font-family: monospace; font-variant: all-petite-caps; } .splash-img { margin: 10% auto 0 auto; width: 512px; background-repeat: no-repeat; height: 512px; animation: color 10s infinite alternate; } .loading { color: white; position: absolute; top: 20%; left: 50%; transform: translateX(-50%); } .loader { width: 300px; height: 300px; border: var(--spacing-md) solid transparent; border-radius: 50%; border-top: var(--spacing-md) solid var(--primary-600); animation: spin 4s linear infinite; position: relative; } diff --git a/modules/api/api.py b/modules/api/api.py index c70a54176..163e11881 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -9,7 +9,7 @@ from fastapi import FastAPI, APIRouter, Depends, Request from fastapi.security import HTTPBasic, HTTPBasicCredentials from fastapi.exceptions import HTTPException from PIL import PngImagePlugin,Image - +import requests import piexif import piexif.helper import gradio as gr @@ -147,6 +147,7 @@ class Api: self.add_api_route("/sdapi/v1/script-info", self.get_script_info, methods=["GET"], response_model=List[models.ScriptInfo]) self.add_api_route("/sdapi/v1/log", self.get_log_buffer, methods=["GET"], response_model=List) # bypass auth self.add_api_route("/sdapi/v1/start", self.session_start, methods=["GET"]) + self.add_api_route("/sdapi/v1/motd", self.get_motd, methods=["GET"], response_model=str) self.add_api_route("/sdapi/v1/extra-networks", self.get_extra_networks, methods=["GET"], response_model=List[models.ExtraNetworkItem]) self.default_script_arg_txt2img = [] self.default_script_arg_img2img = [] @@ -172,6 +173,19 @@ class Api: shared.log.info(f'Browser session: client={req.client.host} agent={agent}') return {} + def get_motd(self): + from installer import get_version + motd = '' + ver = get_version() + if ver.get('updated', None) is not None: + motd = f"version {ver['hash']} {ver['updated']} {ver['url'].split('/')[-1]}
" + if shared.opts.motd: + res = requests.get('https://vladmandic.github.io/automatic/motd', timeout=10) + if res.status_code == 200: + shared.log.info(f'MOTD: {res.text}') + motd += res.text + return motd + def get_selectable_script(self, script_name, script_runner): if script_name is None or script_name == "": return None, None diff --git a/modules/middleware.py b/modules/middleware.py index ead3a3198..e188b4a3d 100644 --- a/modules/middleware.py +++ b/modules/middleware.py @@ -26,7 +26,7 @@ def setup_middleware(app: FastAPI, cmd_opts): from fastapi.middleware.gzip import GZipMiddleware app.user_middleware = [x for x in app.user_middleware if x.cls.__name__ != 'CORSMiddleware'] app.middleware_stack = None # reset current middleware to allow modifying user provided list - app.add_middleware(GZipMiddleware, minimum_size=1024) + app.add_middleware(GZipMiddleware, minimum_size=2048) if cmd_opts.cors_origins and cmd_opts.cors_regex: app.add_middleware(CORSMiddleware, allow_origins=cmd_opts.cors_origins.split(','), allow_origin_regex=cmd_opts.cors_regex, allow_methods=['*'], allow_credentials=True, allow_headers=['*']) elif cmd_opts.cors_origins: diff --git a/modules/shared.py b/modules/shared.py index 656dc9671..970a397f3 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -572,6 +572,7 @@ options_templates.update(options_section(('saving-paths', "Image Naming & Paths" })) options_templates.update(options_section(('ui', "User Interface"), { + "motd": OptionInfo(True, "Show MOTD"), "gradio_theme": OptionInfo("black-teal", "UI theme", gr.Dropdown, lambda: {"choices": list_themes()}, refresh=refresh_themes), "theme_style": OptionInfo("Auto", "Theme mode", gr.Radio, {"choices": ["Auto", "Dark", "Light"]}), "tooltips": OptionInfo("UI Tooltips", "UI tooltips", gr.Radio, {"choices": ["None", "Browser default", "UI tooltips"], "visible": False}), diff --git a/motd b/motd new file mode 100644 index 000000000..0519ecba6 --- /dev/null +++ b/motd @@ -0,0 +1 @@ + \ No newline at end of file