From 6d3a0f43cfda1ed0c920d1f70db2a084677a3d2f Mon Sep 17 00:00:00 2001 From: arcnmx Date: Fri, 3 Mar 2023 13:29:57 -0800 Subject: [PATCH] stable-diffusion-webui --- flake.lock | 19 ++- flake.nix | 5 + modules/aipython3/overlays.nix | 5 + packages/deepdanbooru/default.nix | 24 +++ packages/stable-diffusion/default.nix | 67 +++++++++ packages/tensorflow-io-bin/default.nix | 92 ++++++++++++ projects/webui/default.nix | 18 +++ projects/webui/package.nix | 193 +++++++++++++++++++++++++ projects/webui/path-hacks.patch | 103 +++++++++++++ 9 files changed, 525 insertions(+), 1 deletion(-) create mode 100644 packages/deepdanbooru/default.nix create mode 100644 packages/stable-diffusion/default.nix create mode 100644 packages/tensorflow-io-bin/default.nix create mode 100644 projects/webui/default.nix create mode 100644 projects/webui/package.nix create mode 100644 projects/webui/path-hacks.patch diff --git a/flake.lock b/flake.lock index 3952d258..228af239 100644 --- a/flake.lock +++ b/flake.lock @@ -251,7 +251,24 @@ "hercules-ci-effects": "hercules-ci-effects", "invokeai-src": "invokeai-src", "koboldai-src": "koboldai-src", - "nixpkgs": "nixpkgs_2" + "nixpkgs": "nixpkgs_2", + "webui-src": "webui-src" + } + }, + "webui-src": { + "flake": false, + "locked": { + "lastModified": 1666795088, + "narHash": "sha256-eL6/di8lmSmZ8YFs0a9FuUZadM2TiCOerRqilmK3BfY=", + "owner": "AUTOMATIC1111", + "repo": "stable-diffusion-webui", + "rev": "737eb28faca8be2bb996ee0930ec77d1f7ebd939", + "type": "github" + }, + "original": { + "owner": "AUTOMATIC1111", + "repo": "stable-diffusion-webui", + "type": "github" } } }, diff --git a/flake.nix b/flake.nix index 58a8d014..785d2d03 100644 --- a/flake.nix +++ b/flake.nix @@ -18,6 +18,10 @@ url = "github:koboldai/koboldai-client/1.19.2"; flake = false; }; + webui-src = { + url = "github:AUTOMATIC1111/stable-diffusion-webui"; + flake = false; + }; flake-parts = { url = "github:hercules-ci/flake-parts"; inputs.nixpkgs-lib.follows = "nixpkgs"; @@ -38,6 +42,7 @@ ./modules/aipython3 ./projects/invokeai ./projects/koboldai + ./projects/webui ./website ]; }; diff --git a/modules/aipython3/overlays.nix b/modules/aipython3/overlays.nix index 329d8eff..3c52a8af 100644 --- a/modules/aipython3/overlays.nix +++ b/modules/aipython3/overlays.nix @@ -22,6 +22,7 @@ pkgs: { rmCallPackage = path: args: rm (callPackage path args); in { safetensors = callPackage ../../packages/safetensors { }; + tensorflow-io-bin = callPackage ../../packages/tensorflow-io-bin { }; compel = callPackage ../../packages/compel { }; apispec-webframeworks = callPackage ../../packages/apispec-webframeworks { }; pydeprecate = callPackage ../../packages/pydeprecate { }; @@ -61,6 +62,10 @@ pkgs: { jsonmerge = callPackage ../../packages/jsonmerge { }; clean-fid = callPackage ../../packages/clean-fid { }; getpass-asterisk = callPackage ../../packages/getpass-asterisk { }; + stable-diffusion = callPackage ../../packages/stable-diffusion { }; + deepdanbooru = callPackage ../../packages/deepdanbooru { }; + + tensorflow-io = final.tensorflow-io-bin; }; torchRocm = final: prev: rec { diff --git a/packages/deepdanbooru/default.nix b/packages/deepdanbooru/default.nix new file mode 100644 index 00000000..d2c920f2 --- /dev/null +++ b/packages/deepdanbooru/default.nix @@ -0,0 +1,24 @@ +{ buildPythonPackage +, fetchFromGitHub +, click +, numpy +, scikit-image +, requests +, six +, tensorflow +, tensorflow-io +}: buildPythonPackage rec { + pname = "deepdanbooru"; + version = "2022-10-25"; + src = fetchFromGitHub { + owner = "KichangKim"; + repo = "DeepDanbooru"; + rev = "c48689a85dde0e4a852c1691a7d746abe242e283"; + sha256 = "sha256-IPbh7pEJhn1j1SkCLo0l8955pCFKFn+vPFPtfgW4Zog="; + }; + propagatedBuildInputs = [ + click numpy scikit-image requests six + tensorflow-io tensorflow-io.tensorflow or tensorflow + ]; + doCheck = false; +} diff --git a/packages/stable-diffusion/default.nix b/packages/stable-diffusion/default.nix new file mode 100644 index 00000000..55ee2d29 --- /dev/null +++ b/packages/stable-diffusion/default.nix @@ -0,0 +1,67 @@ +{ + buildPythonPackage +, pythonRelaxDepsHook +, fetchFromGitHub + +, torch +, torchvision +, numpy + +, albumentations +, opencv4 +, pudb +, imageio +, imageio-ffmpeg +, pytorch-lightning +, omegaconf +, test-tube +, streamlit +, einops +, taming-transformers-rom1504 +, torch-fidelity +, torchmetrics +, transformers +, kornia +, k-diffusion +}: +buildPythonPackage rec { + pname = "stable-diffusion"; + version = "2022-08-22"; + + src = fetchFromGitHub { + owner = "CompVis"; + repo = pname; + rev = "69ae4b35e0a0f6ee1af8bb9a5d0016ccb27e36dc"; + sha256 = "sha256-3YkSUATD/73nJFm4os3ZyNU8koabGB/6iR0XbTUQmVY="; + }; + + nativeBuildInputs = [ pythonRelaxDepsHook ]; + pythonRelaxDeps = [ + "transformers" + ]; + + propagatedBuildInputs = [ + torch + torchvision + numpy + + albumentations + opencv4 + pudb + imageio + imageio-ffmpeg + pytorch-lightning + omegaconf + test-tube + streamlit + einops + taming-transformers-rom1504 + torch-fidelity + torchmetrics + transformers + kornia + k-diffusion + ]; + + doCheck = false; +} diff --git a/packages/tensorflow-io-bin/default.nix b/packages/tensorflow-io-bin/default.nix new file mode 100644 index 00000000..2ca69c4a --- /dev/null +++ b/packages/tensorflow-io-bin/default.nix @@ -0,0 +1,92 @@ +{ stdenv +, lib +, fetchurl +, buildPythonPackage +, wheel +, zlib +, python +, keras +, tensorflow +, tensorlow-io-gcs-filesystem ? null +, enableGcsFilesystem ? tensorlow-io-gcs-filesystem != null +}: + +let + version = "0.28.0"; + pname = "tensorflow-io"; + cudaSupport = lib.hasSuffix "-gpu" tensorflow.pname; + + packages = { + /*linux_py_37 = { + url = "https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow_cpu-2.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"; + sha256 = lib.fakeHash; + }; + linux_py_38 = { + url = "https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow_cpu-2.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"; + sha256 = lib.fakeHash; + };*/ + linux_py_39 = { + url = "https://files.pythonhosted.org/packages/91/c8/1ebae5d5583cbe3606d4021e400789ceb0ec9f05169fe6f5a26aa499b867/tensorflow_io-0.28.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl"; + sha256 = "0000000000000000000000000000000000000000000000000009"; + }; + linux_py_310 = { + url = "https://files.pythonhosted.org/packages/d8/39/963bccfbb8f36722a52f2de211ec82f912fb1ddb7a821ccace3739492fe4/tensorflow_io-0.28.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl"; + sha256 = "sha256-Pgu34meOi3JvJREGg0jzUswT5+MJFFwcVfNHmiJ2yTc="; + }; + linux_py_311 = { + url = "https://files.pythonhosted.org/packages/10/e1/0d47af2822777c0ce71539edcb065aca17355b9c276ce95355eedb234c87/tensorflow_io-0.28.0-cp311-cp311-manylinux_2_12_x86_64.manylinux2010_x86_64.whl"; + sha256 = lib.fakeHash; + }; + }; +in buildPythonPackage { + pname = "tensorflow-io"; + inherit version; + format = "wheel"; + + src = let + pyVerNoDot = lib.strings.stringAsChars (x: if x == "." then "" else x) python.pythonVersion; + platform = if stdenv.isDarwin then "mac" else "linux"; + key = "${platform}_py_${pyVerNoDot}"; + in fetchurl packages.${key}; + + propagatedBuildInputs = [ + tensorflow + keras + ] ++ lib.optional (enableGcsFilesystem) tensorlow-io-gcs-filesystem; + + nativeBuildInputs = [ wheel ]; + + inherit enableGcsFilesystem; + preConfigure = '' + unset SOURCE_DATE_EPOCH + + # Make sure that dist and the wheel file are writable. + chmod u+rwx -R ./dist + + pushd dist + + orig_name="$(echo ./*.whl)" + wheel unpack --dest unpacked ./*.whl + rm ./*.whl + + pushd unpacked/tensorflow_io* + if [[ -z ''${enableGcsFilesystem-} ]]; then + sed -i *.dist-info/METADATA \ + -e "/Requires-Dist: tensorflow-io-gcs-filesystem/d" + fi + popd + + wheel pack ./unpacked/tensorflow_io* + mv *.whl $orig_name # avoid changes to the _os_arch.whl suffix + + popd + ''; + + pythonImportsCheck = [ + "tensorflow_io" + ]; + + passthru = { + inherit tensorflow; + }; +} diff --git a/projects/webui/default.nix b/projects/webui/default.nix new file mode 100644 index 00000000..81f9a2b6 --- /dev/null +++ b/projects/webui/default.nix @@ -0,0 +1,18 @@ +{ inputs, lib, ... }: + +{ + perSystem = { config, pkgs, ... }: let + inherit (config.dependencySets) aipython3-amd aipython3-nvidia; + + src = inputs.webui-src; + in { + packages = { + webui-amd = aipython3-amd.callPackage ./package.nix { + inherit src; + }; + webui-nvidia = aipython3-nvidia.callPackage ./package.nix { + inherit src; + }; + }; + }; +} diff --git a/projects/webui/package.nix b/projects/webui/package.nix new file mode 100644 index 00000000..651ff0e5 --- /dev/null +++ b/projects/webui/package.nix @@ -0,0 +1,193 @@ +{ + buildPythonPackage +, pythonRelaxDepsHook +, fetchFromGitHub +, stable-diffusion +, python +, lndir +, src + +, taming-transformers-rom1504 +, transformers +, k-diffusion + +, realesrgan +, pillow + +, addict +, future +, lmdb +, pyyaml +, scikitimage +, tqdm +, yapf +, gdown +, lpips +, fastapi +, lark +, analytics-python +, ffmpy +, markdown-it-py +, shap +, gradio +, fonts +, font-roboto +, piexif +, websockets +, codeformer +, blip +, deepdanbooru +, timm +, fairscale +, inflection + +, diffusers +}@args: +let + submodel = pkg: "${pkg}/${pkg.pythonModule.sitePackages or python.sitePackages}"; +in +buildPythonPackage { + pname = "stable-diffusion-webui"; + version = if src ? lastModifiedDate + then builtins.substring 0 8 src.lastModifiedDate + else "0"; + + inherit src; + + patches = [ + ./path-hacks.patch + ]; + + stable_diffusion = stable-diffusion.src; + taming_transformers = submodel taming-transformers-rom1504; + k_diffusion = submodel k-diffusion; + codeformer = "${submodel codeformer}/codeformer"; + blip = "${submodel blip}/blip"; + + postPatch = '' + substituteAll $setupPath setup.py + + mkdir repositories + ln -s $stable_diffusion repositories/stable-diffusion + substituteAllInPlace modules/paths.py + mkdir -p models/{hypernetworks,Codeformer,ESRGAN,facelib/weights,GFPGAN,LDSR,SwinIR} + + for script_file in launch.py webui.py scripts/*.py; do + sed -i '1 i #!/usr/bin/env python' $script_file + done + ''; + + pythonRelaxDeps = [ "fairscale" "timm" "transformers" ]; + pythonRemoveDeps = [ "invisible-watermark" "opencv-python" ]; + + dontRewriteSymlinks = true; + + inherit (python) sitePackages; + dataPaths = [ "artists.csv" "models" "embeddings" "extensions" "textual_inversion_templates" "repositories" ]; + scriptDirs = [ "javascript" "localizations" ]; + scriptFiles = [ "style.css" "script.js" ]; + postInstall = '' + install -d $out/lib/stable-diffusion-webui + for data_path in $dataPaths; do + mv $data_path $out/lib/stable-diffusion-webui/ + done + for script_path in $scriptDirs; do + install -d $out/lib/stable-diffusion-webui/$script_path + lndir -silent $out/$sitePackages/$script_path $out/lib/stable-diffusion-webui/$script_path + done + for script_file in $scriptFiles; do + ln -s $out/$sitePackages/$script_file $out/lib/stable-diffusion-webui/ + done + + substituteAll $wrapperPath $out/bin/webui + chmod +x $out/bin/* + ''; + + passAsFile = [ "setup" "wrapper" ]; + setup = '' + from io import open + from glob import glob + from setuptools import find_packages, setup + + with open('requirements.txt') as f: + requirements = f.read().splitlines() + + setup( + name='@pname@', + version='@version@', + install_requires=requirements, + py_modules=['webui'], + packages=['modules'] + glob('modules/*/'), + scripts=[ + 'launch.py', 'webui.py', + ] + glob('scripts/*.py'), + package_data = { + 'modules': [ + '../style.css', + '../script.js', + '../javascript/*.js', + '../localizations/*.json', + ], + }, + ) + ''; + + wrapper = '' + if [[ -z ''${SD_WEBUI_SCRIPT_PATH-} ]]; then + export SD_WEBUI_SCRIPT_PATH=''${XDG_DATA_HOME-$HOME/.local/share/stable-diffusion-webui} + fi + if [[ -d $SD_WEBUI_SCRIPT_PATH ]]; then + find "$SD_WEBUI_SCRIPT_PATH" -type l -lname "${builtins.storeDir}/*-@pname@-*/*" -delete + else + mkdir -p "$SD_WEBUI_SCRIPT_PATH" + fi + cp -nr --no-preserve=mode @out@/lib/stable-diffusion-webui/* "$SD_WEBUI_SCRIPT_PATH" + cd "$SD_WEBUI_SCRIPT_PATH" + exec @out@/bin/webui.py "$@" + ''; + + nativeBuildInputs = [ + lndir + pythonRelaxDepsHook + ]; + propagatedBuildInputs = [ + stable-diffusion + realesrgan + diffusers + pillow + addict + future + lmdb + pyyaml + scikitimage + tqdm + yapf + gdown + lpips + fastapi + lark + analytics-python + ffmpy + markdown-it-py + shap + gradio + fonts + font-roboto + piexif + websockets + codeformer + blip + deepdanbooru + timm + fairscale + inflection + ]; + + doCheck = false; + + meta = { + description = "Stable Diffusion web UI"; + homepage = "https://github.com/AUTOMATIC1111/stable-diffusion-webui"; + mainProgram = "webui"; + }; +} diff --git a/projects/webui/path-hacks.patch b/projects/webui/path-hacks.patch new file mode 100644 index 00000000..4371a273 --- /dev/null +++ b/projects/webui/path-hacks.patch @@ -0,0 +1,103 @@ +diff --git a/launch.py b/launch.py +index 8affd410..394436e9 100644 +--- a/launch.py ++++ b/launch.py +@@ -176,16 +176,16 @@ def prepare_enviroment(): + + os.makedirs(dir_repos, exist_ok=True) + +- git_clone(stable_diffusion_repo, repo_dir('stable-diffusion'), "Stable Diffusion", stable_diffusion_commit_hash) +- git_clone(taming_transformers_repo, repo_dir('taming-transformers'), "Taming Transformers", taming_transformers_commit_hash) +- git_clone(k_diffusion_repo, repo_dir('k-diffusion'), "K-diffusion", k_diffusion_commit_hash) +- git_clone(codeformer_repo, repo_dir('CodeFormer'), "CodeFormer", codeformer_commit_hash) +- git_clone(blip_repo, repo_dir('BLIP'), "BLIP", blip_commit_hash) ++ #git_clone(stable_diffusion_repo, repo_dir('stable-diffusion'), "Stable Diffusion", stable_diffusion_commit_hash) ++ #git_clone(taming_transformers_repo, repo_dir('taming-transformers'), "Taming Transformers", taming_transformers_commit_hash) ++ #git_clone(k_diffusion_repo, repo_dir('k-diffusion'), "K-diffusion", k_diffusion_commit_hash) ++ #git_clone(codeformer_repo, repo_dir('CodeFormer'), "CodeFormer", codeformer_commit_hash) ++ #git_clone(blip_repo, repo_dir('BLIP'), "BLIP", blip_commit_hash) + + if not is_installed("lpips"): + run_pip(f"install -r {os.path.join(repo_dir('CodeFormer'), 'requirements.txt')}", "requirements for CodeFormer") + +- run_pip(f"install -r {requirements_file}", "requirements for Web UI") ++ #run_pip(f"install -r {requirements_file}", "requirements for Web UI") + + if update_check: + version_check(commit) +diff --git a/modules/deepbooru.py b/modules/deepbooru.py +index 8bbc90a4..3b13f24d 100644 +--- a/modules/deepbooru.py ++++ b/modules/deepbooru.py +@@ -88,8 +88,9 @@ def get_deepbooru_tags_model(): + import deepdanbooru as dd + import tensorflow as tf + import numpy as np ++ from modules.paths import models_path + this_folder = os.path.dirname(__file__) +- model_path = os.path.abspath(os.path.join(this_folder, '..', 'models', 'deepbooru')) ++ model_path = os.path.abspath(os.path.join(models_path, 'deepbooru')) + if not os.path.exists(os.path.join(model_path, 'project.json')): + # there is no point importing these every time + import zipfile +diff --git a/modules/modelloader.py b/modules/modelloader.py +index b0f2f33d..45d0c726 100644 +--- a/modules/modelloader.py ++++ b/modules/modelloader.py +@@ -120,11 +120,9 @@ def move_files(src_path: str, dest_path: str, ext_filter: str = None): + + + def load_upscalers(): +- sd = shared.script_path + # We can only do this 'magic' method to dynamically load upscalers if they are referenced, + # so we'll try to import any _model.py files before looking in __subclasses__ +- modules_dir = os.path.join(sd, "modules") +- for file in os.listdir(modules_dir): ++ for file in os.listdir(shared.modules_path): + if "_model.py" in file: + model_name = file.replace("_model.py", "") + full_model = f"modules.{model_name}_model" +diff --git a/modules/paths.py b/modules/paths.py +index 1e7a2fbc..2d6e1a59 100644 +--- a/modules/paths.py ++++ b/modules/paths.py +@@ -3,8 +3,9 @@ import os + import sys + import modules.safe + +-script_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) +-models_path = os.path.join(script_path, "models") ++modules_path = os.path.dirname(os.path.dirname(__file__)) ++script_path = os.environ.get('SD_WEBUI_SCRIPT_PATH', '@out@/lib/stable-diffusion-webui') ++models_path = os.environ.get('SD_WEBUI_MODELS_PATH', os.path.join(script_path, "models")) + sys.path.insert(0, script_path) + + # search for directory of stable diffusion in following places +@@ -19,10 +20,10 @@ assert sd_path is not None, "Couldn't find Stable Diffusion in any of: " + str(p + + path_dirs = [ + (sd_path, 'ldm', 'Stable Diffusion', []), +- (os.path.join(sd_path, '../taming-transformers'), 'taming', 'Taming Transformers', []), +- (os.path.join(sd_path, '../CodeFormer'), 'inference_codeformer.py', 'CodeFormer', []), +- (os.path.join(sd_path, '../BLIP'), 'models/blip.py', 'BLIP', []), +- (os.path.join(sd_path, '../k-diffusion'), 'k_diffusion/sampling.py', 'k_diffusion', ["atstart"]), ++ ('@taming_transformers@', 'taming', 'Taming Transformers', []), ++ ('@codeformer@', 'inference_codeformer.py', 'CodeFormer', []), ++ ('@blip@', 'models/blip.py', 'BLIP', []), ++ ('@k_diffusion@', 'k_diffusion/sampling.py', 'k_diffusion', ["atstart"]), + ] + + paths = {} +diff --git a/modules/shared.py b/modules/shared.py +index 1a9b8289..3335128f 100644 +--- a/modules/shared.py ++++ b/modules/shared.py +@@ -16,7 +16,7 @@ import modules.styles + import modules.devices as devices + from modules import sd_samplers, sd_models, localization + from modules.hypernetworks import hypernetwork +-from modules.paths import models_path, script_path, sd_path ++from modules.paths import models_path, script_path, modules_path, sd_path + + sd_model_file = os.path.join(script_path, 'model.ckpt') + default_sd_model_file = sd_model_file