diff --git a/.eslintrc.json b/.eslintrc.json
index ca36cce73..3d73788c3 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -68,11 +68,11 @@
"switch_to_extras": "readonly",
"get_tab_index": "readonly",
"create_submit_args": "readonly",
- "restart_reload": "readonly",
+ "restartReload": "readonly",
"updateInput": "readonly",
"toggleCompact": "readonly",
// settings.js
- "register_drag_drop": "readonly",
+ "registerDragDrop": "readonly",
//extraNetworks.js
"requestGet": "readonly",
"getENActiveTab": "readonly",
diff --git a/.gitignore b/.gitignore
index ec0afa225..32c9bf88d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,6 +58,8 @@ cache
.idea/
/localizations
-# unexcluded so folders get created
+# force included
!/models/VAE-approx
!/models/VAE-approx/model.pt
+!/models/Reference
+!/models/Reference/**/*
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b7edc215d..1b8dbdce2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,9 @@ Also, [Wiki](https://github.com/vladmandic/automatic/wiki) has been updated with
Some highlights: [OpenVINO](https://github.com/vladmandic/automatic/wiki/OpenVINO), [IntelArc](https://github.com/vladmandic/automatic/wiki/Intel-ARC), [DirectML](https://github.com/vladmandic/automatic/wiki/DirectML), [ONNX/Olive>](https://github.com/vladmandic/automatic/wiki/ONNX-Runtime)
- **Diffusers**
+ - since now **SD.Next** supports **12** different model types, we've added reference model for each type in
+ *Extra networks -> Reference* for easier select & auto-download
+ Models can still be downloaded manually, this is just a convenience feature & a showcase for supported models
- new model type: [Segmind SSD-1B](https://huggingface.co/segmind/SSD-1B)
its a *distilled* model, this time 50% smaller and faster version of SD-XL!
(and quality does not suffer, its just more optimized)
diff --git a/html/reference.json b/html/reference.json
new file mode 100644
index 000000000..4a1ad9d34
--- /dev/null
+++ b/html/reference.json
@@ -0,0 +1,40 @@
+{
+ "RunwayML SD 1.5": {
+ "path": "runwayml/stable-diffusion-v1-5"
+ },
+ "StabilityAI SD 2.1": {
+ "path": "stabilityai/stable-diffusion-2-1-base"
+ },
+ "StabilityAI SD-XL 1.0 Base": {
+ "path": "stabilityai/stable-diffusion-xl-base-1.0"
+ },
+ "Segmind SSD-1B": {
+ "path": "segmind/SSD-1B"
+ },
+ "Segmind Tiny": {
+ "path": "segmind/tiny-sd"
+ },
+ "LCM Dreamshaper 7": {
+ "path": "SimianLuo/LCM_Dreamshaper_v7"
+ },
+ "Warp Wuerstchen": {
+ "path": "warp-ai/wuerstchen"
+ },
+ "Kandinsky 2.1": {
+ "path": "kandinsky-community/kandinsky-2-1"
+ },
+ "Kandinsky 2.2": {
+ "path": "kandinsky-community/kandinsky-2-2-decoder"
+ },
+ "DeepFloyd IF Medium": {
+ "path": "DeepFloyd/IF-I-M-v1.0"
+ },
+ "Tsinghua UniDiffuser": {
+ "path": "thu-ml/unidiffuser-v1",
+ "desc": "UniDiffuser is a unified diffusion framework to fit all distributions relevant to a set of multi-modal data in one transformer. UniDiffuser is able to perform image, text, text-to-image, image-to-text, and image-text pair generation by setting proper timesteps without additional overhead.\nSpecifically, UniDiffuser employs a variation of transformer, called U-ViT, which parameterizes the joint noise prediction network. Other components perform as encoders and decoders of different modalities, including a pretrained image autoencoder from Stable Diffusion, a pretrained image ViT-B/32 CLIP encoder, a pretrained text ViT-L CLIP encoder, and a GPT-2 text decoder finetuned by ourselves.",
+ "preview": "unidiffuser-v1.jpg"
+ },
+ "Sudo-AI Zero123": {
+ "path": "sudo-ai/zero123plus-v1.1"
+ }
+}
diff --git a/installer.py b/installer.py
index c44e27a63..01a48ad8e 100644
--- a/installer.py
+++ b/installer.py
@@ -508,8 +508,6 @@ def check_torch():
import xformers
if torch.__version__ != '2.0.1+cu118' and xformers.__version__ in ['0.0.22', '0.0.21', '0.0.20']:
log.warning(f'Likely incompatible torch with: xformers=={xformers.__version__} installed: torch=={torch.__version__} required: torch==2.1.0+cu118 - build xformers manually or downgrade torch')
- if 'cu118' not in torch.__version__:
- log.warning(f'Likely incompatible Cuda with: xformers=={xformers.__version__} installed: torch=={torch.__version__} required: torch==2.1.0+cu118 - build xformers manually or downgrade torch')
elif not args.experimental and not args.use_xformers:
uninstall('xformers')
except Exception as e:
diff --git a/javascript/extensions.js b/javascript/extensions.js
index 1e56a9a36..f94f9b57d 100644
--- a/javascript/extensions.js
+++ b/javascript/extensions.js
@@ -5,7 +5,7 @@ function extensions_apply(extensions_disabled_list, extensions_update_list, disa
if (x.name.startsWith('enable_') && !x.checked) disable.push(x.name.substring(7));
if (x.name.startsWith('update_') && x.checked) update.push(x.name.substring(7));
});
- restart_reload();
+ restartReload();
log('Extensions apply:', { disable, update });
return [JSON.stringify(disable), JSON.stringify(update), disable_all];
}
diff --git a/javascript/settings.js b/javascript/settings.js
index 3cd84b52a..dacc8bd87 100644
--- a/javascript/settings.js
+++ b/javascript/settings.js
@@ -89,7 +89,7 @@ onAfterUiUpdate(async () => {
const jsdata = textarea.value;
updateOpts(jsdata);
executeCallbacks(optionsChangedCallbacks);
- register_drag_drop();
+ registerDragDrop();
Object.defineProperty(textarea, 'value', {
set(newValue) {
diff --git a/javascript/ui.js b/javascript/ui.js
index 028cc9fd9..8581fa3db 100644
--- a/javascript/ui.js
+++ b/javascript/ui.js
@@ -211,7 +211,7 @@ function recalculate_prompts_inpaint(...args) {
return Array.from(arguments);
}
-function register_drag_drop() {
+function registerDragDrop() {
const qs = gradioApp().getElementById('quicksettings');
if (!qs) return;
qs.addEventListener('dragover', (evt) => {
@@ -297,7 +297,7 @@ function getTranslation(...args) {
return null;
}
-function monitor_server_status() {
+function monitorServerStatus() {
document.open();
document.write(`
@@ -305,12 +305,12 @@ function monitor_server_status() {
Waiting for server...
@@ -318,12 +318,12 @@ function monitor_server_status() {
document.close();
}
-function restart_reload() {
+function restartReload() {
document.body.style = 'background: #222222; font-size: 1rem; font-family:monospace; margin-top:20%; color:lightgray; text-align:center';
document.body.innerHTML = 'Server shutdown in progress...
';
fetch('/sdapi/v1/progress')
- .then((res) => setTimeout(restart_reload, 1000))
- .catch((e) => setTimeout(monitor_server_status, 500));
+ .then((res) => setTimeout(restartReload, 1000))
+ .catch((e) => setTimeout(monitorServerStatus, 500));
return [];
}
@@ -351,6 +351,12 @@ function selectVAE(name) {
log(`Change VAE: ${desiredVAEName}`);
}
+function selectReference(name) {
+ console.log('HERE', name);
+ desiredCheckpointName = name;
+ gradioApp().getElementById('change_reference').click();
+}
+
function currentImg2imgSourceResolution(_a, _b, scaleBy) {
const img = gradioApp().querySelector('#mode_img2img > div[style="display: block;"] img');
return img ? [img.naturalWidth, img.naturalHeight, scaleBy] : [0, 0, scaleBy];
@@ -361,7 +367,7 @@ function updateImg2imgResizeToTextAfterChangingImage() {
return [];
}
-function create_theme_element() {
+function createThemeElement() {
const el = document.createElement('img');
el.id = 'theme-preview';
el.className = 'theme-preview';
@@ -393,7 +399,7 @@ function previewTheme() {
if (theme) {
window.open(theme.subdomain, '_blank');
} else {
- const el = document.getElementById('theme-preview') || create_theme_element();
+ const el = document.getElementById('theme-preview') || createThemeElement();
el.style.display = el.style.display === 'block' ? 'none' : 'block';
name = name.replace('/', '-');
el.src = `/file=html/${name}.jpg`;
diff --git a/models/Reference/unidiffuser-v1.jpg b/models/Reference/unidiffuser-v1.jpg
new file mode 100644
index 000000000..72f104c95
Binary files /dev/null and b/models/Reference/unidiffuser-v1.jpg differ
diff --git a/modules/modelloader.py b/modules/modelloader.py
index 86cfdf3c7..4d4858cec 100644
--- a/modules/modelloader.py
+++ b/modules/modelloader.py
@@ -213,21 +213,24 @@ def download_diffusers_model(hub_id: str, cache_dir: str = None, download_config
pipeline_dir = None
ok = True
+ err = None
try:
pipeline_dir = DiffusionPipeline.download(hub_id, **download_config)
except Exception as e:
+ err = e
ok = False
- shared.log.warning(f"Diffusers download error: {hub_id} {e}")
- if not ok:
+ # shared.log.warning(f"Diffusers download error: {hub_id} {e}")
+ if not ok and 'Repository Not Found' not in str(err):
try:
download_config.pop('load_connected_pipeline')
download_config.pop('variant')
pipeline_dir = hf.snapshot_download(hub_id, **download_config)
- except Exception as e:
- shared.log.warning(f"Diffusers hub download error: {hub_id} {e}")
+ except Exception:
+ # shared.log.warning(f"Diffusers download error: {hub_id} {e}")
+ pass
if pipeline_dir is None:
- shared.log.error(f"Diffusers no pipeline folder: {hub_id}")
+ shared.log.error(f"Diffusers download error: {hub_id} {err}")
return None
try:
# TODO diffusers is this real error?
@@ -314,6 +317,23 @@ def find_diffuser(name: str):
return None
+def load_reference(name: str):
+ found = [r for r in diffuser_repos if name == r['name'] or name == r['friendly'] or name == r['path']]
+ if len(found) > 0: # already downloaded
+ shared.log.debug(f'Reference model: {found[0]}')
+ return True
+ shared.log.debug(f'Reference download: {name}')
+ model_dir = download_diffusers_model(name, shared.opts.diffusers_dir)
+ if model_dir is None:
+ shared.log.debug(f'Reference download failed: {name}')
+ return False
+ else:
+ shared.log.debug(f'Reference download complete: {name}')
+ from modules import sd_models
+ sd_models.list_models()
+ return True
+
+
modelloader_directories = {}
cache_last = 0
cache_time = 1
diff --git a/modules/ui.py b/modules/ui.py
index 361c82e23..f18fc1456 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -1157,9 +1157,9 @@ def reload_sd_weights():
inputs=components,
outputs=[text_settings, result],
)
- defaults_submit.click(fn=lambda: modules.shared.restore_defaults(restart=True), _js="restart_reload")
- restart_submit.click(fn=lambda: modules.shared.restart_server(restart=True), _js="restart_reload")
- shutdown_submit.click(fn=lambda: modules.shared.restart_server(restart=False), _js="restart_reload")
+ defaults_submit.click(fn=lambda: modules.shared.restore_defaults(restart=True), _js="restartReload")
+ restart_submit.click(fn=lambda: modules.shared.restart_server(restart=True), _js="restartReload")
+ shutdown_submit.click(fn=lambda: modules.shared.restart_server(restart=False), _js="restartReload")
for _i, k, _item in quicksettings_list:
component = component_dict[k]
@@ -1194,6 +1194,21 @@ def reload_sd_weights():
outputs=[component_dict['sd_vae'], text_settings],
)
+ def reference_submit(model):
+ from modules import modelloader
+ loaded = modelloader.load_reference(model)
+ if loaded:
+ return model if loaded else opts.sd_model_checkpoint
+ print('HERE', model, loaded)
+ return loaded
+
+ button_set_reference = gr.Button('Change reference', elem_id='change_reference', visible=False)
+ button_set_reference.click(
+ fn=reference_submit,
+ _js="function(v){ return desiredCheckpointName; }",
+ inputs=[component_dict['sd_model_checkpoint']],
+ outputs=[component_dict['sd_model_checkpoint']],
+ )
component_keys = [k for k in opts.data_labels.keys() if k in component_dict]
def get_settings_values():
diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py
index 9a9257d39..1804a1199 100644
--- a/modules/ui_extra_networks.py
+++ b/modules/ui_extra_networks.py
@@ -15,10 +15,11 @@
import gradio as gr
from PIL import Image
from starlette.responses import FileResponse, JSONResponse
-from modules import shared, scripts, modelloader
+from modules import paths, shared, scripts, modelloader
from modules.ui_components import ToolButton
import modules.ui_symbols as symbols
+
allowed_dirs = []
dir_cache = {} # key=path, value=(mtime, listdir(path))
refresh_time = 0
@@ -238,8 +239,11 @@ def create_page(self, tabname, skip = False):
allowed_folders = [os.path.abspath(x) for x in self.allowed_directories_for_previews()]
for parentdir, dirs in {d: modelloader.directory_directories(d) for d in allowed_folders}.items():
for tgt in dirs.keys():
- if shared.opts.diffusers_dir in tgt:
- subdirs[os.path.basename(shared.opts.diffusers_dir)] = 1
+ if shared.backend == shared.Backend.DIFFUSERS:
+ if os.path.join(paths.models_path, 'Reference') in tgt:
+ subdirs['Reference'] = 1
+ if shared.opts.diffusers_dir in tgt:
+ subdirs[os.path.basename(shared.opts.diffusers_dir)] = 1
if 'models--' in tgt:
continue
subdir = tgt[len(parentdir):].replace("\\", "/")
@@ -737,7 +741,7 @@ def ui_scan_click(title):
return ui_refresh_click(title)
def ui_save_click():
- from modules import paths, generation_parameters_copypaste
+ from modules import generation_parameters_copypaste
filename = os.path.join(paths.data_path, "params.txt")
if os.path.exists(filename):
with open(filename, "r", encoding="utf8") as file:
@@ -749,7 +753,7 @@ def ui_save_click():
return res
def ui_quicksave_click(name):
- from modules import paths, generation_parameters_copypaste
+ from modules import generation_parameters_copypaste
fn = os.path.join(paths.data_path, "params.txt")
if os.path.exists(fn):
with open(fn, "r", encoding="utf8") as file:
diff --git a/modules/ui_extra_networks_checkpoints.py b/modules/ui_extra_networks_checkpoints.py
index ee01e54cd..30849c088 100644
--- a/modules/ui_extra_networks_checkpoints.py
+++ b/modules/ui_extra_networks_checkpoints.py
@@ -1,8 +1,9 @@
import html
import json
import os
-from modules import shared, ui_extra_networks, sd_models
+from modules import shared, ui_extra_networks, sd_models, paths
+reference_dir = os.path.join(paths.models_path, 'Reference')
class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage):
def __init__(self):
@@ -11,11 +12,35 @@ def __init__(self):
def refresh(self):
shared.refresh_checkpoints()
+ def list_reference(self):
+ if shared.backend != shared.Backend.DIFFUSERS:
+ return []
+ reference_models = shared.readfile(os.path.join('html', 'reference.json'))
+ for k, v in reference_models.items():
+ name = os.path.join(reference_dir, k)
+ yield {
+ "type": 'Model',
+ "name": name,
+ "title": name,
+ "filename": v['path'],
+ "search_term": self.search_terms_from_path(name),
+ "preview": self.find_preview(os.path.join(reference_dir, os.path.basename(v['path']))),
+ "local_preview": f"{os.path.splitext(name)[0]}.{shared.opts.samples_format}",
+ "onclick": '"' + html.escape(f"""return selectReference({json.dumps(v['path'])})""") + '"',
+ "hash": None,
+ "mtime": 0,
+ "size": 0,
+ "info": {},
+ "metadata": {},
+ "description": v.get('desc', ''),
+ }
+
def list_items(self):
checkpoint: sd_models.CheckpointInfo
checkpoints = sd_models.checkpoints_list.copy()
for name, checkpoint in checkpoints.items():
try:
+ exists = os.path.exists(checkpoint.filename)
record = {
"type": 'Model',
"name": checkpoint.name,
@@ -27,14 +52,16 @@ def list_items(self):
"local_preview": f"{os.path.splitext(checkpoint.filename)[0]}.{shared.opts.samples_format}",
"metadata": checkpoint.metadata,
"onclick": '"' + html.escape(f"""return selectCheckpoint({json.dumps(name)})""") + '"',
- "mtime": os.path.getmtime(checkpoint.filename),
- "size": os.path.getsize(checkpoint.filename),
+ "mtime": os.path.getmtime(checkpoint.filename) if exists else 0,
+ "size": os.path.getsize(checkpoint.filename) if exists else 0,
}
record["info"] = self.find_info(checkpoint.filename)
record["description"] = self.find_description(checkpoint.filename, record["info"])
yield record
except Exception as e:
shared.log.debug(f"Extra networks error: type=model file={name} {e}")
+ for record in self.list_reference():
+ yield record
def allowed_directories_for_previews(self):
- return [v for v in [shared.opts.ckpt_dir, shared.opts.diffusers_dir, sd_models.model_path] if v is not None]
+ return [v for v in [shared.opts.ckpt_dir, shared.opts.diffusers_dir, reference_dir, sd_models.model_path] if v is not None]