Merge branch 'master' into fix-ckpt-cache
commit
fb3b564801
@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
function extensions_apply(_, _){
|
||||||
|
disable = []
|
||||||
|
update = []
|
||||||
|
gradioApp().querySelectorAll('#extensions input[type="checkbox"]').forEach(function(x){
|
||||||
|
if(x.name.startsWith("enable_") && ! x.checked)
|
||||||
|
disable.push(x.name.substr(7))
|
||||||
|
|
||||||
|
if(x.name.startsWith("update_") && x.checked)
|
||||||
|
update.push(x.name.substr(7))
|
||||||
|
})
|
||||||
|
|
||||||
|
restart_reload()
|
||||||
|
|
||||||
|
return [JSON.stringify(disable), JSON.stringify(update)]
|
||||||
|
}
|
||||||
|
|
||||||
|
function extensions_check(){
|
||||||
|
gradioApp().querySelectorAll('#extensions .extension_status').forEach(function(x){
|
||||||
|
x.innerHTML = "Loading..."
|
||||||
|
})
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
function install_extension_from_index(button, url){
|
||||||
|
button.disabled = "disabled"
|
||||||
|
button.value = "Installing..."
|
||||||
|
|
||||||
|
textarea = gradioApp().querySelector('#extension_to_install textarea')
|
||||||
|
textarea.value = url
|
||||||
|
textarea.dispatchEvent(new Event("input", { bubbles: true }))
|
||||||
|
|
||||||
|
gradioApp().querySelector('#install_extension_button').click()
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,83 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
import git
|
||||||
|
|
||||||
|
from modules import paths, shared
|
||||||
|
|
||||||
|
|
||||||
|
extensions = []
|
||||||
|
extensions_dir = os.path.join(paths.script_path, "extensions")
|
||||||
|
|
||||||
|
|
||||||
|
def active():
|
||||||
|
return [x for x in extensions if x.enabled]
|
||||||
|
|
||||||
|
|
||||||
|
class Extension:
|
||||||
|
def __init__(self, name, path, enabled=True):
|
||||||
|
self.name = name
|
||||||
|
self.path = path
|
||||||
|
self.enabled = enabled
|
||||||
|
self.status = ''
|
||||||
|
self.can_update = False
|
||||||
|
|
||||||
|
repo = None
|
||||||
|
try:
|
||||||
|
if os.path.exists(os.path.join(path, ".git")):
|
||||||
|
repo = git.Repo(path)
|
||||||
|
except Exception:
|
||||||
|
print(f"Error reading github repository info from {path}:", file=sys.stderr)
|
||||||
|
print(traceback.format_exc(), file=sys.stderr)
|
||||||
|
|
||||||
|
if repo is None or repo.bare:
|
||||||
|
self.remote = None
|
||||||
|
else:
|
||||||
|
self.remote = next(repo.remote().urls, None)
|
||||||
|
self.status = 'unknown'
|
||||||
|
|
||||||
|
def list_files(self, subdir, extension):
|
||||||
|
from modules import scripts
|
||||||
|
|
||||||
|
dirpath = os.path.join(self.path, subdir)
|
||||||
|
if not os.path.isdir(dirpath):
|
||||||
|
return []
|
||||||
|
|
||||||
|
res = []
|
||||||
|
for filename in sorted(os.listdir(dirpath)):
|
||||||
|
res.append(scripts.ScriptFile(self.path, filename, os.path.join(dirpath, filename)))
|
||||||
|
|
||||||
|
res = [x for x in res if os.path.splitext(x.path)[1].lower() == extension and os.path.isfile(x.path)]
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
def check_updates(self):
|
||||||
|
repo = git.Repo(self.path)
|
||||||
|
for fetch in repo.remote().fetch("--dry-run"):
|
||||||
|
if fetch.flags != fetch.HEAD_UPTODATE:
|
||||||
|
self.can_update = True
|
||||||
|
self.status = "behind"
|
||||||
|
return
|
||||||
|
|
||||||
|
self.can_update = False
|
||||||
|
self.status = "latest"
|
||||||
|
|
||||||
|
def pull(self):
|
||||||
|
repo = git.Repo(self.path)
|
||||||
|
repo.remotes.origin.pull()
|
||||||
|
|
||||||
|
|
||||||
|
def list_extensions():
|
||||||
|
extensions.clear()
|
||||||
|
|
||||||
|
if not os.path.isdir(extensions_dir):
|
||||||
|
return
|
||||||
|
|
||||||
|
for dirname in sorted(os.listdir(extensions_dir)):
|
||||||
|
path = os.path.join(extensions_dir, dirname)
|
||||||
|
if not os.path.isdir(path):
|
||||||
|
continue
|
||||||
|
|
||||||
|
extension = Extension(name=dirname, path=path, enabled=dirname not in shared.opts.disabled_extensions)
|
||||||
|
extensions.append(extension)
|
||||||
@ -0,0 +1,207 @@
|
|||||||
|
import torch
|
||||||
|
import os
|
||||||
|
from collections import namedtuple
|
||||||
|
from modules import shared, devices, script_callbacks
|
||||||
|
from modules.paths import models_path
|
||||||
|
import glob
|
||||||
|
|
||||||
|
|
||||||
|
model_dir = "Stable-diffusion"
|
||||||
|
model_path = os.path.abspath(os.path.join(models_path, model_dir))
|
||||||
|
vae_dir = "VAE"
|
||||||
|
vae_path = os.path.abspath(os.path.join(models_path, vae_dir))
|
||||||
|
|
||||||
|
|
||||||
|
vae_ignore_keys = {"model_ema.decay", "model_ema.num_updates"}
|
||||||
|
|
||||||
|
|
||||||
|
default_vae_dict = {"auto": "auto", "None": "None"}
|
||||||
|
default_vae_list = ["auto", "None"]
|
||||||
|
|
||||||
|
|
||||||
|
default_vae_values = [default_vae_dict[x] for x in default_vae_list]
|
||||||
|
vae_dict = dict(default_vae_dict)
|
||||||
|
vae_list = list(default_vae_list)
|
||||||
|
first_load = True
|
||||||
|
|
||||||
|
|
||||||
|
base_vae = None
|
||||||
|
loaded_vae_file = None
|
||||||
|
checkpoint_info = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_base_vae(model):
|
||||||
|
if base_vae is not None and checkpoint_info == model.sd_checkpoint_info and model:
|
||||||
|
return base_vae
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def store_base_vae(model):
|
||||||
|
global base_vae, checkpoint_info
|
||||||
|
if checkpoint_info != model.sd_checkpoint_info:
|
||||||
|
base_vae = model.first_stage_model.state_dict().copy()
|
||||||
|
checkpoint_info = model.sd_checkpoint_info
|
||||||
|
|
||||||
|
|
||||||
|
def delete_base_vae():
|
||||||
|
global base_vae, checkpoint_info
|
||||||
|
base_vae = None
|
||||||
|
checkpoint_info = None
|
||||||
|
|
||||||
|
|
||||||
|
def restore_base_vae(model):
|
||||||
|
global base_vae, checkpoint_info
|
||||||
|
if base_vae is not None and checkpoint_info == model.sd_checkpoint_info:
|
||||||
|
load_vae_dict(model, base_vae)
|
||||||
|
delete_base_vae()
|
||||||
|
|
||||||
|
|
||||||
|
def get_filename(filepath):
|
||||||
|
return os.path.splitext(os.path.basename(filepath))[0]
|
||||||
|
|
||||||
|
|
||||||
|
def refresh_vae_list(vae_path=vae_path, model_path=model_path):
|
||||||
|
global vae_dict, vae_list
|
||||||
|
res = {}
|
||||||
|
candidates = [
|
||||||
|
*glob.iglob(os.path.join(model_path, '**/*.vae.ckpt'), recursive=True),
|
||||||
|
*glob.iglob(os.path.join(model_path, '**/*.vae.pt'), recursive=True),
|
||||||
|
*glob.iglob(os.path.join(vae_path, '**/*.ckpt'), recursive=True),
|
||||||
|
*glob.iglob(os.path.join(vae_path, '**/*.pt'), recursive=True)
|
||||||
|
]
|
||||||
|
if shared.cmd_opts.vae_path is not None and os.path.isfile(shared.cmd_opts.vae_path):
|
||||||
|
candidates.append(shared.cmd_opts.vae_path)
|
||||||
|
for filepath in candidates:
|
||||||
|
name = get_filename(filepath)
|
||||||
|
res[name] = filepath
|
||||||
|
vae_list.clear()
|
||||||
|
vae_list.extend(default_vae_list)
|
||||||
|
vae_list.extend(list(res.keys()))
|
||||||
|
vae_dict.clear()
|
||||||
|
vae_dict.update(res)
|
||||||
|
vae_dict.update(default_vae_dict)
|
||||||
|
return vae_list
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_vae(checkpoint_file, vae_file="auto"):
|
||||||
|
global first_load, vae_dict, vae_list
|
||||||
|
|
||||||
|
# if vae_file argument is provided, it takes priority, but not saved
|
||||||
|
if vae_file and vae_file not in default_vae_list:
|
||||||
|
if not os.path.isfile(vae_file):
|
||||||
|
vae_file = "auto"
|
||||||
|
print("VAE provided as function argument doesn't exist")
|
||||||
|
# for the first load, if vae-path is provided, it takes priority, saved, and failure is reported
|
||||||
|
if first_load and shared.cmd_opts.vae_path is not None:
|
||||||
|
if os.path.isfile(shared.cmd_opts.vae_path):
|
||||||
|
vae_file = shared.cmd_opts.vae_path
|
||||||
|
shared.opts.data['sd_vae'] = get_filename(vae_file)
|
||||||
|
else:
|
||||||
|
print("VAE provided as command line argument doesn't exist")
|
||||||
|
# else, we load from settings
|
||||||
|
if vae_file == "auto" and shared.opts.sd_vae is not None:
|
||||||
|
# if saved VAE settings isn't recognized, fallback to auto
|
||||||
|
vae_file = vae_dict.get(shared.opts.sd_vae, "auto")
|
||||||
|
# if VAE selected but not found, fallback to auto
|
||||||
|
if vae_file not in default_vae_values and not os.path.isfile(vae_file):
|
||||||
|
vae_file = "auto"
|
||||||
|
print("Selected VAE doesn't exist")
|
||||||
|
# vae-path cmd arg takes priority for auto
|
||||||
|
if vae_file == "auto" and shared.cmd_opts.vae_path is not None:
|
||||||
|
if os.path.isfile(shared.cmd_opts.vae_path):
|
||||||
|
vae_file = shared.cmd_opts.vae_path
|
||||||
|
print("Using VAE provided as command line argument")
|
||||||
|
# if still not found, try look for ".vae.pt" beside model
|
||||||
|
model_path = os.path.splitext(checkpoint_file)[0]
|
||||||
|
if vae_file == "auto":
|
||||||
|
vae_file_try = model_path + ".vae.pt"
|
||||||
|
if os.path.isfile(vae_file_try):
|
||||||
|
vae_file = vae_file_try
|
||||||
|
print("Using VAE found beside selected model")
|
||||||
|
# if still not found, try look for ".vae.ckpt" beside model
|
||||||
|
if vae_file == "auto":
|
||||||
|
vae_file_try = model_path + ".vae.ckpt"
|
||||||
|
if os.path.isfile(vae_file_try):
|
||||||
|
vae_file = vae_file_try
|
||||||
|
print("Using VAE found beside selected model")
|
||||||
|
# No more fallbacks for auto
|
||||||
|
if vae_file == "auto":
|
||||||
|
vae_file = None
|
||||||
|
# Last check, just because
|
||||||
|
if vae_file and not os.path.exists(vae_file):
|
||||||
|
vae_file = None
|
||||||
|
|
||||||
|
return vae_file
|
||||||
|
|
||||||
|
|
||||||
|
def load_vae(model, vae_file=None):
|
||||||
|
global first_load, vae_dict, vae_list, loaded_vae_file
|
||||||
|
# save_settings = False
|
||||||
|
|
||||||
|
if vae_file:
|
||||||
|
print(f"Loading VAE weights from: {vae_file}")
|
||||||
|
vae_ckpt = torch.load(vae_file, map_location=shared.weight_load_location)
|
||||||
|
vae_dict_1 = {k: v for k, v in vae_ckpt["state_dict"].items() if k[0:4] != "loss" and k not in vae_ignore_keys}
|
||||||
|
load_vae_dict(model, vae_dict_1)
|
||||||
|
|
||||||
|
# If vae used is not in dict, update it
|
||||||
|
# It will be removed on refresh though
|
||||||
|
vae_opt = get_filename(vae_file)
|
||||||
|
if vae_opt not in vae_dict:
|
||||||
|
vae_dict[vae_opt] = vae_file
|
||||||
|
vae_list.append(vae_opt)
|
||||||
|
|
||||||
|
loaded_vae_file = vae_file
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Save current VAE to VAE settings, maybe? will it work?
|
||||||
|
if save_settings:
|
||||||
|
if vae_file is None:
|
||||||
|
vae_opt = "None"
|
||||||
|
|
||||||
|
# shared.opts.sd_vae = vae_opt
|
||||||
|
"""
|
||||||
|
|
||||||
|
first_load = False
|
||||||
|
|
||||||
|
|
||||||
|
# don't call this from outside
|
||||||
|
def load_vae_dict(model, vae_dict_1=None):
|
||||||
|
if vae_dict_1:
|
||||||
|
store_base_vae(model)
|
||||||
|
model.first_stage_model.load_state_dict(vae_dict_1)
|
||||||
|
else:
|
||||||
|
restore_base_vae()
|
||||||
|
model.first_stage_model.to(devices.dtype_vae)
|
||||||
|
|
||||||
|
|
||||||
|
def reload_vae_weights(sd_model=None, vae_file="auto"):
|
||||||
|
from modules import lowvram, devices, sd_hijack
|
||||||
|
|
||||||
|
if not sd_model:
|
||||||
|
sd_model = shared.sd_model
|
||||||
|
|
||||||
|
checkpoint_info = sd_model.sd_checkpoint_info
|
||||||
|
checkpoint_file = checkpoint_info.filename
|
||||||
|
vae_file = resolve_vae(checkpoint_file, vae_file=vae_file)
|
||||||
|
|
||||||
|
if loaded_vae_file == vae_file:
|
||||||
|
return
|
||||||
|
|
||||||
|
if shared.cmd_opts.lowvram or shared.cmd_opts.medvram:
|
||||||
|
lowvram.send_everything_to_cpu()
|
||||||
|
else:
|
||||||
|
sd_model.to(devices.cpu)
|
||||||
|
|
||||||
|
sd_hijack.model_hijack.undo_hijack(sd_model)
|
||||||
|
|
||||||
|
load_vae(sd_model, vae_file)
|
||||||
|
|
||||||
|
sd_hijack.model_hijack.hijack(sd_model)
|
||||||
|
script_callbacks.model_loaded_callback(sd_model)
|
||||||
|
|
||||||
|
if not shared.cmd_opts.lowvram and not shared.cmd_opts.medvram:
|
||||||
|
sd_model.to(devices.device)
|
||||||
|
|
||||||
|
print(f"VAE Weights loaded.")
|
||||||
|
return sd_model
|
||||||
@ -0,0 +1,268 @@
|
|||||||
|
import json
|
||||||
|
import os.path
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
import git
|
||||||
|
|
||||||
|
import gradio as gr
|
||||||
|
import html
|
||||||
|
|
||||||
|
from modules import extensions, shared, paths
|
||||||
|
|
||||||
|
|
||||||
|
available_extensions = {"extensions": []}
|
||||||
|
|
||||||
|
|
||||||
|
def check_access():
|
||||||
|
assert not shared.cmd_opts.disable_extension_access, "extension access disabed because of commandline flags"
|
||||||
|
|
||||||
|
|
||||||
|
def apply_and_restart(disable_list, update_list):
|
||||||
|
check_access()
|
||||||
|
|
||||||
|
disabled = json.loads(disable_list)
|
||||||
|
assert type(disabled) == list, f"wrong disable_list data for apply_and_restart: {disable_list}"
|
||||||
|
|
||||||
|
update = json.loads(update_list)
|
||||||
|
assert type(update) == list, f"wrong update_list data for apply_and_restart: {update_list}"
|
||||||
|
|
||||||
|
update = set(update)
|
||||||
|
|
||||||
|
for ext in extensions.extensions:
|
||||||
|
if ext.name not in update:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
ext.pull()
|
||||||
|
except Exception:
|
||||||
|
print(f"Error pulling updates for {ext.name}:", file=sys.stderr)
|
||||||
|
print(traceback.format_exc(), file=sys.stderr)
|
||||||
|
|
||||||
|
shared.opts.disabled_extensions = disabled
|
||||||
|
shared.opts.save(shared.config_filename)
|
||||||
|
|
||||||
|
shared.state.interrupt()
|
||||||
|
shared.state.need_restart = True
|
||||||
|
|
||||||
|
|
||||||
|
def check_updates():
|
||||||
|
check_access()
|
||||||
|
|
||||||
|
for ext in extensions.extensions:
|
||||||
|
if ext.remote is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
ext.check_updates()
|
||||||
|
except Exception:
|
||||||
|
print(f"Error checking updates for {ext.name}:", file=sys.stderr)
|
||||||
|
print(traceback.format_exc(), file=sys.stderr)
|
||||||
|
|
||||||
|
return extension_table()
|
||||||
|
|
||||||
|
|
||||||
|
def extension_table():
|
||||||
|
code = f"""<!-- {time.time()} -->
|
||||||
|
<table id="extensions">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><abbr title="Use checkbox to enable the extension; it will be enabled or disabled when you click apply button">Extension</abbr></th>
|
||||||
|
<th>URL</th>
|
||||||
|
<th><abbr title="Use checkbox to mark the extension for update; it will be updated when you click apply button">Update</abbr></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
"""
|
||||||
|
|
||||||
|
for ext in extensions.extensions:
|
||||||
|
if ext.can_update:
|
||||||
|
ext_status = f"""<label><input class="gr-check-radio gr-checkbox" name="update_{html.escape(ext.name)}" checked="checked" type="checkbox">{html.escape(ext.status)}</label>"""
|
||||||
|
else:
|
||||||
|
ext_status = ext.status
|
||||||
|
|
||||||
|
code += f"""
|
||||||
|
<tr>
|
||||||
|
<td><label><input class="gr-check-radio gr-checkbox" name="enable_{html.escape(ext.name)}" type="checkbox" {'checked="checked"' if ext.enabled else ''}>{html.escape(ext.name)}</label></td>
|
||||||
|
<td><a href="{html.escape(ext.remote or '')}">{html.escape(ext.remote or '')}</a></td>
|
||||||
|
<td{' class="extension_status"' if ext.remote is not None else ''}>{ext_status}</td>
|
||||||
|
</tr>
|
||||||
|
"""
|
||||||
|
|
||||||
|
code += """
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
"""
|
||||||
|
|
||||||
|
return code
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_git_url(url):
|
||||||
|
if url is None:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
url = url.replace(".git", "")
|
||||||
|
return url
|
||||||
|
|
||||||
|
|
||||||
|
def install_extension_from_url(dirname, url):
|
||||||
|
check_access()
|
||||||
|
|
||||||
|
assert url, 'No URL specified'
|
||||||
|
|
||||||
|
if dirname is None or dirname == "":
|
||||||
|
*parts, last_part = url.split('/')
|
||||||
|
last_part = normalize_git_url(last_part)
|
||||||
|
|
||||||
|
dirname = last_part
|
||||||
|
|
||||||
|
target_dir = os.path.join(extensions.extensions_dir, dirname)
|
||||||
|
assert not os.path.exists(target_dir), f'Extension directory already exists: {target_dir}'
|
||||||
|
|
||||||
|
normalized_url = normalize_git_url(url)
|
||||||
|
assert len([x for x in extensions.extensions if normalize_git_url(x.remote) == normalized_url]) == 0, 'Extension with this URL is already installed'
|
||||||
|
|
||||||
|
tmpdir = os.path.join(paths.script_path, "tmp", dirname)
|
||||||
|
|
||||||
|
try:
|
||||||
|
shutil.rmtree(tmpdir, True)
|
||||||
|
|
||||||
|
repo = git.Repo.clone_from(url, tmpdir)
|
||||||
|
repo.remote().fetch()
|
||||||
|
|
||||||
|
os.rename(tmpdir, target_dir)
|
||||||
|
|
||||||
|
extensions.list_extensions()
|
||||||
|
return [extension_table(), html.escape(f"Installed into {target_dir}. Use Installed tab to restart.")]
|
||||||
|
finally:
|
||||||
|
shutil.rmtree(tmpdir, True)
|
||||||
|
|
||||||
|
|
||||||
|
def install_extension_from_index(url):
|
||||||
|
ext_table, message = install_extension_from_url(None, url)
|
||||||
|
|
||||||
|
return refresh_available_extensions_from_data(), ext_table, message
|
||||||
|
|
||||||
|
|
||||||
|
def refresh_available_extensions(url):
|
||||||
|
global available_extensions
|
||||||
|
|
||||||
|
import urllib.request
|
||||||
|
with urllib.request.urlopen(url) as response:
|
||||||
|
text = response.read()
|
||||||
|
|
||||||
|
available_extensions = json.loads(text)
|
||||||
|
|
||||||
|
return url, refresh_available_extensions_from_data(), ''
|
||||||
|
|
||||||
|
|
||||||
|
def refresh_available_extensions_from_data():
|
||||||
|
extlist = available_extensions["extensions"]
|
||||||
|
installed_extension_urls = {normalize_git_url(extension.remote): extension.name for extension in extensions.extensions}
|
||||||
|
|
||||||
|
code = f"""<!-- {time.time()} -->
|
||||||
|
<table id="available_extensions">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Extension</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
"""
|
||||||
|
|
||||||
|
for ext in extlist:
|
||||||
|
name = ext.get("name", "noname")
|
||||||
|
url = ext.get("url", None)
|
||||||
|
description = ext.get("description", "")
|
||||||
|
|
||||||
|
if url is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
existing = installed_extension_urls.get(normalize_git_url(url), None)
|
||||||
|
|
||||||
|
install_code = f"""<input onclick="install_extension_from_index(this, '{html.escape(url)}')" type="button" value="{"Install" if not existing else "Installed"}" {"disabled=disabled" if existing else ""} class="gr-button gr-button-lg gr-button-secondary">"""
|
||||||
|
|
||||||
|
code += f"""
|
||||||
|
<tr>
|
||||||
|
<td><a href="{html.escape(url)}">{html.escape(name)}</a></td>
|
||||||
|
<td>{html.escape(description)}</td>
|
||||||
|
<td>{install_code}</td>
|
||||||
|
</tr>
|
||||||
|
"""
|
||||||
|
|
||||||
|
code += """
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
"""
|
||||||
|
|
||||||
|
return code
|
||||||
|
|
||||||
|
|
||||||
|
def create_ui():
|
||||||
|
import modules.ui
|
||||||
|
|
||||||
|
with gr.Blocks(analytics_enabled=False) as ui:
|
||||||
|
with gr.Tabs(elem_id="tabs_extensions") as tabs:
|
||||||
|
with gr.TabItem("Installed"):
|
||||||
|
|
||||||
|
with gr.Row():
|
||||||
|
apply = gr.Button(value="Apply and restart UI", variant="primary")
|
||||||
|
check = gr.Button(value="Check for updates")
|
||||||
|
extensions_disabled_list = gr.Text(elem_id="extensions_disabled_list", visible=False).style(container=False)
|
||||||
|
extensions_update_list = gr.Text(elem_id="extensions_update_list", visible=False).style(container=False)
|
||||||
|
|
||||||
|
extensions_table = gr.HTML(lambda: extension_table())
|
||||||
|
|
||||||
|
apply.click(
|
||||||
|
fn=apply_and_restart,
|
||||||
|
_js="extensions_apply",
|
||||||
|
inputs=[extensions_disabled_list, extensions_update_list],
|
||||||
|
outputs=[],
|
||||||
|
)
|
||||||
|
|
||||||
|
check.click(
|
||||||
|
fn=check_updates,
|
||||||
|
_js="extensions_check",
|
||||||
|
inputs=[],
|
||||||
|
outputs=[extensions_table],
|
||||||
|
)
|
||||||
|
|
||||||
|
with gr.TabItem("Available"):
|
||||||
|
with gr.Row():
|
||||||
|
refresh_available_extensions_button = gr.Button(value="Load from:", variant="primary")
|
||||||
|
available_extensions_index = gr.Text(value="https://raw.githubusercontent.com/wiki/AUTOMATIC1111/stable-diffusion-webui/Extensions-index.md", label="Extension index URL").style(container=False)
|
||||||
|
extension_to_install = gr.Text(elem_id="extension_to_install", visible=False)
|
||||||
|
install_extension_button = gr.Button(elem_id="install_extension_button", visible=False)
|
||||||
|
|
||||||
|
install_result = gr.HTML()
|
||||||
|
available_extensions_table = gr.HTML()
|
||||||
|
|
||||||
|
refresh_available_extensions_button.click(
|
||||||
|
fn=modules.ui.wrap_gradio_call(refresh_available_extensions, extra_outputs=[gr.update(), gr.update()]),
|
||||||
|
inputs=[available_extensions_index],
|
||||||
|
outputs=[available_extensions_index, available_extensions_table, install_result],
|
||||||
|
)
|
||||||
|
|
||||||
|
install_extension_button.click(
|
||||||
|
fn=modules.ui.wrap_gradio_call(install_extension_from_index, extra_outputs=[gr.update(), gr.update()]),
|
||||||
|
inputs=[extension_to_install],
|
||||||
|
outputs=[available_extensions_table, extensions_table, install_result],
|
||||||
|
)
|
||||||
|
|
||||||
|
with gr.TabItem("Install from URL"):
|
||||||
|
install_url = gr.Text(label="URL for extension's git repository")
|
||||||
|
install_dirname = gr.Text(label="Local directory name", placeholder="Leave empty for auto")
|
||||||
|
install_button = gr.Button(value="Install", variant="primary")
|
||||||
|
install_result = gr.HTML(elem_id="extension_install_result")
|
||||||
|
|
||||||
|
install_button.click(
|
||||||
|
fn=modules.ui.wrap_gradio_call(install_extension_from_url, extra_outputs=[gr.update()]),
|
||||||
|
inputs=[install_dirname, install_url],
|
||||||
|
outputs=[extensions_table, install_result],
|
||||||
|
)
|
||||||
|
|
||||||
|
return ui
|
||||||
Loading…
Reference in New Issue