|
|
from IPython.display import display, Image, clear_output |
|
|
from IPython import get_ipython |
|
|
from ipywidgets import widgets |
|
|
from pathlib import Path |
|
|
import subprocess |
|
|
import argparse |
|
|
import shlex |
|
|
import json |
|
|
import sys |
|
|
import os |
|
|
import re |
|
|
|
|
|
SyS = get_ipython().system |
|
|
CD = os.chdir |
|
|
iRON = os.environ |
|
|
|
|
|
REPO = { |
|
|
'A1111': 'https://github.com/gutris1/A1111', |
|
|
'Forge': 'https://github.com/lllyasviel/stable-diffusion-webui-forge Forge', |
|
|
'ReForge': '-b main-old https://github.com/Panchovix/stable-diffusion-webui-reForge ReForge', |
|
|
'Forge-Classic': 'https://github.com/Haoming02/sd-webui-forge-classic Forge-Classic', |
|
|
'Forge-Neo': '-b neo https://github.com/Haoming02/sd-webui-forge-classic Forge-Neo', |
|
|
'ComfyUI': 'https://github.com/comfyanonymous/ComfyUI', |
|
|
'SwarmUI': 'https://github.com/mcmonkeyprojects/SwarmUI' |
|
|
} |
|
|
|
|
|
WEBUI_LIST = ['A1111', 'Forge', 'ReForge', 'Forge-Classic', 'Forge-Neo', 'ComfyUI', 'SwarmUI'] |
|
|
|
|
|
def getENV(): |
|
|
env = { |
|
|
'Colab': ('/content', '/content', 'COLAB_JUPYTER_TOKEN'), |
|
|
'Kaggle': ('/kaggle', '/kaggle/working', 'KAGGLE_DATA_PROXY_TOKEN') |
|
|
} |
|
|
for name, (base, home, var) in env.items(): |
|
|
if var in iRON: |
|
|
return name, base, home |
|
|
return None, None, None |
|
|
|
|
|
def getArgs(): |
|
|
parser = argparse.ArgumentParser(description='WebUI Installer Script for Kaggle and Google Colab') |
|
|
parser.add_argument('--webui', required=True, help='available webui: A1111, Forge, ReForge, Forge-Classic, Forge-Neo, ComfyUI, SwarmUI') |
|
|
parser.add_argument('--civitai_key', required=True, help='your CivitAI API key') |
|
|
parser.add_argument('--hf_read_token', default=None, help='your Huggingface READ Token (optional)') |
|
|
|
|
|
args, unknown = parser.parse_known_args() |
|
|
|
|
|
arg1 = args.webui.lower() |
|
|
arg2 = args.civitai_key.strip() |
|
|
arg3 = args.hf_read_token.strip() if args.hf_read_token else '' |
|
|
|
|
|
if not any(arg1 == option.lower() for option in WEBUI_LIST): |
|
|
print(f'{ERROR}: invalid webui option: "{args.webui}"') |
|
|
print(f'Available webui options: {", ".join(WEBUI_LIST)}') |
|
|
return None, None, None |
|
|
|
|
|
if not arg2: |
|
|
print(f'{ERROR}: CivitAI API key is missing.') |
|
|
return None, None, None |
|
|
if re.search(r'\s+', arg2): |
|
|
print(f'{ERROR}: CivitAI API key contains spaces "{arg2}" - not allowed.') |
|
|
return None, None, None |
|
|
if len(arg2) < 32: |
|
|
print(f'{ERROR}: CivitAI API key must be at least 32 characters long.') |
|
|
return None, None, None |
|
|
|
|
|
if not arg3: arg3 = '' |
|
|
if re.search(r'\s+', arg3): arg3 = '' |
|
|
|
|
|
selected_ui = next(option for option in WEBUI_LIST if arg1 == option.lower()) |
|
|
return selected_ui, arg2, arg3 |
|
|
|
|
|
def getPython(): |
|
|
hao = webui in ['Forge-Classic', 'Forge-Neo'] |
|
|
v = '3.11' if hao else '3.10' |
|
|
BIN = str(PY / 'bin') |
|
|
PKG = str(PY / f'lib/python{v}/site-packages') |
|
|
|
|
|
tar = { |
|
|
**dict.fromkeys(['ComfyUI', 'SwarmUI'], 'https://huggingface.co/gutris1/webui/resolve/main/env/KC-ComfyUI-SwarmUI-Python310-Torch260-cu124.tar.lz4'), |
|
|
'Forge-Classic': 'https://huggingface.co/gutris1/webui/resolve/main/env/KC-FC-Python311-Torch260-cu124.tar.lz4', |
|
|
'Forge-Neo': 'https://huggingface.co/gutris1/webui/resolve/main/env/KC-FN-Python311-Torch280-cu126.tar.lz4', |
|
|
} |
|
|
|
|
|
url = tar.get(webui, 'https://huggingface.co/gutris1/webui/resolve/main/env/KC-Python310-Torch260-cu124.tar.lz4') |
|
|
|
|
|
fn = Path(url).name |
|
|
|
|
|
CD(Path(ENVBASE).parent) |
|
|
print(f"\n{ARROW} installing Python Portable {'3.11.13' if hao else '3.10.15'}") |
|
|
|
|
|
SyS('sudo apt-get -qq -y install aria2 pv lz4 > /dev/null 2>&1') |
|
|
|
|
|
aria = f'aria2c --console-log-level=error --stderr=true -c -x16 -s16 -k1M -j5 {url} -o {fn}' |
|
|
p = subprocess.Popen(shlex.split(aria), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) |
|
|
p.wait() |
|
|
|
|
|
SyS(f'pv {fn} | lz4 -d | tar -xf -') |
|
|
Path(f'/{fn}').unlink() |
|
|
|
|
|
sys.path.insert(0, PKG) |
|
|
if BIN not in iRON['PATH']: |
|
|
iRON['PATH'] = BIN + ':' + iRON['PATH'] |
|
|
if PKG not in iRON['PYTHONPATH']: |
|
|
iRON['PYTHONPATH'] = PKG + ':' + iRON['PYTHONPATH'] |
|
|
|
|
|
if ENVNAME == 'Kaggle': |
|
|
for cmd in [ |
|
|
'pip install ipywidgets jupyterlab_widgets --upgrade', |
|
|
'rm -f /usr/lib/python3.10/sitecustomize.py' |
|
|
]: |
|
|
SyS(f'{cmd} > /dev/null 2>&1') |
|
|
|
|
|
def marking(p, n, u): |
|
|
t = p / n |
|
|
v = {'ui': u, 'launch_args': '', 'tunnel': ''} |
|
|
|
|
|
if not t.exists(): t.write_text(json.dumps(v, indent=4)) |
|
|
|
|
|
d = json.loads(t.read_text()) |
|
|
d.update(v) |
|
|
t.write_text(json.dumps(d, indent=4)) |
|
|
|
|
|
def key_inject(C, H): |
|
|
p = Path(nenen) |
|
|
v = p.read_text() |
|
|
v = v.replace("TOKET = ''", f"TOKET = '{C}'") |
|
|
v = v.replace("TOBRUT = ''", f"TOBRUT = '{H}'") |
|
|
p.write_text(v) |
|
|
|
|
|
def install_tunnel(): |
|
|
SyS(f'wget -qO {USR}/cl https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64') |
|
|
SyS(f'chmod +x {USR}/cl') |
|
|
|
|
|
bins = { |
|
|
'zrok': { |
|
|
'bin': USR / 'zrok', |
|
|
'url': 'https://github.com/openziti/zrok/releases/download/v1.0.6/zrok_1.0.6_linux_amd64.tar.gz' |
|
|
}, |
|
|
'ngrok': { |
|
|
'bin': USR / 'ngrok', |
|
|
'url': 'https://bin.equinox.io/c/bNyj1mQVY4c/ngrok-v3-stable-linux-amd64.tgz' |
|
|
} |
|
|
} |
|
|
|
|
|
for n, b in bins.items(): |
|
|
if b['bin'].exists(): b['bin'].unlink() |
|
|
|
|
|
url = b['url'] |
|
|
name = Path(url).name |
|
|
|
|
|
SyS(f'wget -qO {name} {url}') |
|
|
SyS(f'tar -xzf {name} -C {USR}') |
|
|
SyS(f'rm -f {name}') |
|
|
|
|
|
def sym_link(U, M): |
|
|
configs = { |
|
|
'A1111': { |
|
|
'sym': [ |
|
|
f"rm -rf {M / 'Stable-diffusion/tmp_ckpt'} {M / 'Lora/tmp_lora'} {M / 'ControlNet'} {TMP}/*" |
|
|
], |
|
|
'links': [ |
|
|
(TMP / 'ckpt', M / 'Stable-diffusion/tmp_ckpt'), |
|
|
(TMP / 'lora', M / 'Lora/tmp_lora'), |
|
|
(TMP / 'controlnet', M / 'ControlNet') |
|
|
] |
|
|
}, |
|
|
|
|
|
'Forge': { |
|
|
'sym': [ |
|
|
f"rm -rf {M / 'Stable-diffusion/tmp_ckpt'} {M / 'Lora/tmp_lora'} {M / 'ControlNet'}", |
|
|
f"rm -rf {M / 'svd'} {M / 'z123'} {M / 'clip'} {M / 'clip_vision'} {M / 'diffusers'}", |
|
|
f"rm -rf {M / 'diffusion_models'} {M / 'text_encoder'} {M / 'unet'} {TMP}/*" |
|
|
], |
|
|
'links': [ |
|
|
(TMP / 'ckpt', M / 'Stable-diffusion/tmp_ckpt'), |
|
|
(TMP / 'lora', M / 'Lora/tmp_lora'), |
|
|
(TMP / 'controlnet', M / 'ControlNet'), |
|
|
(TMP / 'z123', M / 'z123'), |
|
|
(TMP / 'svd', M / 'svd'), |
|
|
(TMP / 'clip', M / 'clip'), |
|
|
(TMP / 'clip_vision', M / 'clip_vision'), |
|
|
(TMP / 'diffusers', M / 'diffusers'), |
|
|
(TMP / 'diffusion_models', M / 'diffusion_models'), |
|
|
(TMP / 'text_encoders', M / 'text_encoder'), |
|
|
(TMP / 'unet', M / 'unet') |
|
|
] |
|
|
}, |
|
|
|
|
|
'ReForge': { |
|
|
'sym': [ |
|
|
f"rm -rf {M / 'Stable-diffusion/tmp_ckpt'} {M / 'Lora/tmp_lora'} {M / 'ControlNet'}", |
|
|
f"rm -rf {M / 'svd'} {M / 'z123'} {TMP}/*" |
|
|
], |
|
|
'links': [ |
|
|
(TMP / 'ckpt', M / 'Stable-diffusion/tmp_ckpt'), |
|
|
(TMP / 'lora', M / 'Lora/tmp_lora'), |
|
|
(TMP / 'controlnet', M / 'ControlNet'), |
|
|
(TMP / 'z123', M / 'z123'), |
|
|
(TMP / 'svd', M / 'svd') |
|
|
] |
|
|
}, |
|
|
|
|
|
'Forge-Classic': { |
|
|
'sym': [ |
|
|
f"rm -rf {M / 'Stable-diffusion/tmp_ckpt'} {M / 'Lora/tmp_lora'} {M / 'ControlNet'}" |
|
|
], |
|
|
'links': [ |
|
|
(TMP / 'ckpt', M / 'Stable-diffusion/tmp_ckpt'), |
|
|
(TMP / 'lora', M / 'Lora/tmp_lora'), |
|
|
(TMP / 'controlnet', M / 'ControlNet') |
|
|
] |
|
|
}, |
|
|
|
|
|
'Forge-Neo': { |
|
|
'sym': [ |
|
|
f"rm -rf {M / 'Stable-diffusion/tmp_ckpt'} {M / 'Lora/tmp_lora'} {M / 'ControlNet'}" |
|
|
], |
|
|
'links': [ |
|
|
(TMP / 'ckpt', M / 'Stable-diffusion/tmp_ckpt'), |
|
|
(TMP / 'lora', M / 'Lora/tmp_lora'), |
|
|
(TMP / 'controlnet', M / 'ControlNet') |
|
|
] |
|
|
}, |
|
|
|
|
|
'ComfyUI': { |
|
|
'sym': [ |
|
|
f"rm -rf {M / 'checkpoints/tmp_ckpt'} {M / 'loras/tmp_lora'} {M / 'controlnet'}", |
|
|
f"rm -rf {M / 'clip'} {M / 'clip_vision'} {M / 'diffusers'} {M / 'diffusion_models'}", |
|
|
f"rm -rf {M / 'text_encoders'} {M / 'unet'} {TMP}/*" |
|
|
], |
|
|
'links': [ |
|
|
(TMP / 'ckpt', M / 'checkpoints/tmp_ckpt'), |
|
|
(TMP / 'lora', M / 'loras/tmp_lora'), |
|
|
(TMP / 'controlnet', M / 'controlnet'), |
|
|
(TMP / 'clip', M / 'clip'), |
|
|
(TMP / 'clip_vision', M / 'clip_vision'), |
|
|
(TMP / 'diffusers', M / 'diffusers'), |
|
|
(TMP / 'diffusion_models', M / 'diffusion_models'), |
|
|
(TMP / 'text_encoders', M / 'text_encoders'), |
|
|
(TMP / 'unet', M / 'unet') |
|
|
] |
|
|
}, |
|
|
|
|
|
'SwarmUI': { |
|
|
'sym': [ |
|
|
f"rm -rf {M / 'Stable-Diffusion/tmp_ckpt'} {M / 'Lora/tmp_lora'} {M / 'controlnet'}", |
|
|
f"rm -rf {M / 'clip'} {M / 'unet'} {TMP}/*" |
|
|
], |
|
|
'links': [ |
|
|
(TMP / 'ckpt', M / 'Stable-Diffusion/tmp_ckpt'), |
|
|
(TMP / 'lora', M / 'Lora/tmp_lora'), |
|
|
(TMP / 'controlnet', M / 'controlnet'), |
|
|
(TMP / 'clip', M / 'clip'), |
|
|
(TMP / 'unet', M / 'unet') |
|
|
] |
|
|
} |
|
|
} |
|
|
|
|
|
cfg = configs.get(U) |
|
|
[SyS(f'{cmd}') for cmd in cfg['sym']] |
|
|
if U not in ['ComfyUI', 'SwarmUI']: [(M / d).mkdir(parents=True, exist_ok=True) for d in ['Lora', 'ESRGAN']] |
|
|
[SyS(f'ln -s {src} {tg}') for src, tg in cfg['links']] |
|
|
|
|
|
def webui_req(U, W, M): |
|
|
CD(W) |
|
|
|
|
|
if U != 'SwarmUI': |
|
|
pull(f'https://github.com/gutris1/segsmaker {U.lower()} {W}') |
|
|
else: |
|
|
M.mkdir(parents=True, exist_ok=True) |
|
|
for sub in ['Stable-Diffusion', 'Lora', 'Embeddings', 'VAE', 'upscale_models']: |
|
|
(M / sub).mkdir(parents=True, exist_ok=True) |
|
|
|
|
|
download(f'https://dot.net/v1/dotnet-install.sh {W}') |
|
|
dotnet = W / 'dotnet-install.sh' |
|
|
dotnet.chmod(0o755) |
|
|
SyS('bash ./dotnet-install.sh --channel 8.0') |
|
|
|
|
|
sym_link(U, M) |
|
|
install_tunnel() |
|
|
|
|
|
scripts = [ |
|
|
f'https://github.com/gutris1/segsmaker/raw/main/script/controlnet.py {W}/asd', |
|
|
f'https://github.com/gutris1/segsmaker/raw/main/script/KC/segsmaker.py {W}' |
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
for item in scripts: download(item) |
|
|
|
|
|
if U not in ['SwarmUI', 'ComfyUI']: |
|
|
e = 'jpg' if U in ['Forge-Classic', 'Forge-Neo'] else 'png' |
|
|
SyS(f'rm -f {W}/html/card-no-preview.{e}') |
|
|
|
|
|
for ass in [ |
|
|
f'https://huggingface.co/gutris1/webui/resolve/main/misc/card-no-preview.png {W}/html card-no-preview.{e}', |
|
|
f'https://github.com/gutris1/segsmaker/raw/main/config/NoCrypt_miku.json {W}/tmp/gradio_themes', |
|
|
f'https://github.com/gutris1/segsmaker/raw/main/config/user.css {W} user.css' |
|
|
]: download(ass) |
|
|
|
|
|
if U not in ['Forge', 'Forge-Neo']: download(f'https://github.com/gutris1/segsmaker/raw/main/config/config.json {W} config.json') |
|
|
|
|
|
def webui_extension(U, W, M): |
|
|
EXT = W / 'custom_nodes' if U == 'ComfyUI' else W / 'extensions' |
|
|
CD(EXT) |
|
|
|
|
|
if U == 'ComfyUI': |
|
|
say('<br><b>【{red} Installing Custom Nodes{d} 】{red}</b>') |
|
|
clone(str(W / 'asd/custom_nodes.txt')) |
|
|
print() |
|
|
|
|
|
|
|
|
else: |
|
|
say('<br><b>【{red} Installing Extensions{d} 】{red}</b>') |
|
|
clone(str(W / 'asd/extension.txt')) |
|
|
if ENVNAME == 'Kaggle': clone('https://github.com/gutris1/sd-image-encryption') |
|
|
|
|
|
def webui_installation(U, W): |
|
|
M = W / 'Models' if U == 'SwarmUI' else W / 'models' |
|
|
E = M / 'Embeddings' if U == 'SwarmUI' else (M / 'embeddings' if U in ['Forge-Classic', 'Forge-Neo', 'ComfyUI'] else W / 'embeddings') |
|
|
V = M / 'vae' if U == 'ComfyUI' else M / 'VAE' |
|
|
|
|
|
webui_req(U, W, M) |
|
|
|
|
|
|
|
|
|
|
|
if U != 'SwarmUI': webui_extension(U, W, M) |
|
|
|
|
|
def webui_selection(ui): |
|
|
with output: |
|
|
output.clear_output(wait=True) |
|
|
|
|
|
if ui in REPO: (WEBUI, repo) = (HOME / ui, REPO[ui]) |
|
|
say(f'<b>【{{red}} Installing {WEBUI.name}{{d}} 】{{red}}</b>') |
|
|
clone(repo) |
|
|
|
|
|
webui_installation(ui, WEBUI) |
|
|
|
|
|
with loading: |
|
|
loading.clear_output(wait=True) |
|
|
say('<br><b>【{red} Done{d} 】{red}</b>') |
|
|
tempe() |
|
|
CD(HOME) |
|
|
|
|
|
def webui_installer(): |
|
|
branchs = { |
|
|
'A1111': 'master', |
|
|
'ComfyUI': 'master', |
|
|
'SwarmUI': 'master', |
|
|
'Forge': 'main', |
|
|
'ReForge': 'main', |
|
|
'Forge-Classic': 'classic', |
|
|
'Forge-Neo': 'neo', |
|
|
} |
|
|
|
|
|
CD(HOME) |
|
|
ui = (json.load(MARKED.open('r')) if MARKED.exists() else {}).get('ui') |
|
|
WEBUI = HOME / ui if ui else None |
|
|
|
|
|
if WEBUI is not None and WEBUI.exists(): |
|
|
git_dir = WEBUI / '.git' |
|
|
if git_dir.exists(): |
|
|
CD(WEBUI) |
|
|
with output: |
|
|
output.clear_output(wait=True) |
|
|
if ui in branchs: SyS(f'git pull origin {branchs[ui]}') |
|
|
with loading: loading.clear_output() |
|
|
else: |
|
|
try: |
|
|
webui_selection(webui) |
|
|
except KeyboardInterrupt: |
|
|
with loading: loading.clear_output() |
|
|
with output: print('\nCanceled.') |
|
|
except Exception as e: |
|
|
with loading: loading.clear_output() |
|
|
with output: print(f'\n{ERROR}: {e}') |
|
|
|
|
|
def notebook_scripts(): |
|
|
z = [ |
|
|
(STR / '00-startup.py', f'wget -qO {STR}/00-startup.py https://github.com/gutris1/segsmaker/raw/main/script/KC/00-startup.py'), |
|
|
(nenen, f'wget -qO {nenen} https://github.com/gutris1/segsmaker/raw/main/script/nenen88.py'), |
|
|
(melon, f'wget -qO {melon} https://github.com/gutris1/segsmaker/raw/main/script/melon00.py'), |
|
|
(STR / 'cupang.py', f'wget -qO {STR}/cupang.py https://github.com/gutris1/segsmaker/raw/main/script/cupang.py'), |
|
|
(MRK, f'wget -qO {MRK} https://github.com/gutris1/segsmaker/raw/main/script/marking.py') |
|
|
] |
|
|
|
|
|
[SyS(y) for x, y in z if not Path(x).exists()] |
|
|
|
|
|
j = {'ENVNAME': ENVNAME, 'HOMEPATH': HOME, 'TEMPPATH': TMP, 'BASEPATH': Path(ENVBASE)} |
|
|
text = '\n'.join(f"{k} = '{v}'" for k, v in j.items()) |
|
|
Path(KANDANG).write_text(text) |
|
|
|
|
|
key_inject(civitai_key, hf_read_token) |
|
|
marking(SRC, MARKED, webui) |
|
|
sys.path.append(str(STR)) |
|
|
|
|
|
for scripts in [nenen, melon, KANDANG, MRK]: get_ipython().run_line_magic('run', str(scripts)) |
|
|
|
|
|
ENVNAME, ENVBASE, ENVHOME = getENV() |
|
|
|
|
|
if not ENVNAME: |
|
|
print('You are not in Kaggle or Google Colab.\nExiting.') |
|
|
sys.exit() |
|
|
|
|
|
RESET = '\033[0m' |
|
|
RED = '\033[31m' |
|
|
PURPLE = '\033[38;5;135m' |
|
|
ORANGE = '\033[38;5;208m' |
|
|
ARROW = f'{ORANGE}▶{RESET}' |
|
|
ERROR = f'{PURPLE}[{RESET}{RED}ERROR{RESET}{PURPLE}]{RESET}' |
|
|
IMG = 'https://github.com/gutris1/segsmaker/raw/main/script/loading.png' |
|
|
|
|
|
HOME = Path(ENVHOME) |
|
|
TMP = Path(ENVBASE) / 'temp' |
|
|
|
|
|
PY = Path('/GUTRIS1') |
|
|
SRC = HOME / 'gutris1' |
|
|
MRK = SRC / 'marking.py' |
|
|
KEY = SRC / 'api-key.json' |
|
|
MARKED = SRC / 'marking.json' |
|
|
|
|
|
USR = Path('/usr/bin') |
|
|
STR = Path('/root/.ipython/profile_default/startup') |
|
|
nenen = STR / 'nenen88.py' |
|
|
melon = STR / 'melon00.py' |
|
|
KANDANG = STR / 'KANDANG.py' |
|
|
|
|
|
TMP.mkdir(parents=True, exist_ok=True) |
|
|
SRC.mkdir(parents=True, exist_ok=True) |
|
|
|
|
|
output = widgets.Output() |
|
|
loading = widgets.Output() |
|
|
|
|
|
webui, civitai_key, hf_read_token = getArgs() |
|
|
if civitai_key is None: sys.exit() |
|
|
|
|
|
display(output, loading) |
|
|
with loading: display(Image(url=IMG)) |
|
|
with output: PY.exists() or getPython() |
|
|
notebook_scripts() |
|
|
|
|
|
from nenen88 import clone, say, download, tempe, pull |
|
|
webui_installer() |