Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enhancement] Add Automatic1111 Forge #748

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 29 additions & 15 deletions docker-compose.yml
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
x-base_service: &base_service
ports:
- "${WEBUI_PORT:-7860}:7860"
volumes:
- &v1 ./data:/data
- &v2 ./output:/output
stop_signal: SIGKILL
tty: true
deploy:
resources:
reservations:
devices:
- driver: nvidia
device_ids: ['0']
capabilities: [compute, utility]
ports:
- "${WEBUI_PORT:-7860}:7860"
volumes:
- &v1 ./data:/data
- &v2 ./output:/output
stop_signal: SIGKILL
tty: true
deploy:
resources:
reservations:
devices:
- driver: nvidia
device_ids: ["0"]
capabilities: [compute, utility]

name: webui-docker

Expand All @@ -38,6 +38,21 @@ services:
environment:
- CLI_ARGS=--no-half --precision full --allow-code --enable-insecure-extension-access --api

forge: &forge
<<: *base_service
profiles: ["forge"]
build: ./services/AUTOMATIC1111-forge
image: sd-auto-forge:78
environment:
- CLI_ARGS=--allow-code --xformers --enable-insecure-extension-access --api

forge-cpu:
<<: *forge
profiles: ["forge-cpu"]
deploy: {}
environment:
- CLI_ARGS=--no-half --precision full --allow-code --enable-insecure-extension-access --api

comfy: &comfy
<<: *base_service
profiles: ["comfy"]
Expand All @@ -46,7 +61,6 @@ services:
environment:
- CLI_ARGS=


comfy-cpu:
<<: *comfy
profiles: ["comfy-cpu"]
Expand Down
68 changes: 68 additions & 0 deletions services/AUTOMATIC1111-forge/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
FROM alpine/git:latest as download

COPY clone.sh /clone.sh

RUN . /clone.sh stable-diffusion-webui-assets https://github.com/AUTOMATIC1111/stable-diffusion-webui-assets.git 6f7db241d2f8ba7457bac5ca9753331f0c266917

RUN . /clone.sh stable-diffusion-stability-ai https://github.com/Stability-AI/stablediffusion.git cf1d67a6fd5ea1aa600c4df58e5b47da45f6bdbf \
&& rm -rf assets data/**/*.png data/**/*.jpg data/**/*.gif

RUN . /clone.sh BLIP https://github.com/salesforce/BLIP.git 48211a1594f1321b00f14c9f7a5b4813144b2fb9
RUN . /clone.sh k-diffusion https://github.com/crowsonkb/k-diffusion.git ab527a9a6d347f364e3d185ba6d714e22d80cb3c
RUN . /clone.sh clip-interrogator https://github.com/pharmapsychotic/clip-interrogator 2cf03aaf6e704197fd0dae7c7f96aa59cf1b11c9
RUN . /clone.sh generative-models https://github.com/Stability-AI/generative-models 45c443b316737a4ab6e40413d7794a7f5657c19f
RUN . /clone.sh huggingface_guess https://github.com/lllyasviel/huggingface_guess.git 70942022b6bcd17d941c1b4172804175758618e2
RUN . /clone.sh google_blockly_prototypes https://github.com/lllyasviel/google_blockly_prototypes.git 1e98997c7fedaf5106af9849b6f50ebe5c4408f1
RUN . /clone.sh stable-diffusion-webui-assets https://github.com/AUTOMATIC1111/stable-diffusion-webui-assets.git 6f7db241d2f8ba7457bac5ca9753331f0c266917


FROM pytorch/pytorch:2.5.1-cuda12.4-cudnn9-runtime

ENV DEBIAN_FRONTEND=noninteractive PIP_PREFER_BINARY=1

RUN --mount=type=cache,target=/var/cache/apt \
apt-get update && \
# we need those
apt-get install -y fonts-dejavu-core rsync git jq moreutils aria2 \
# extensions needs those
ffmpeg libglfw3-dev libgles2-mesa-dev pkg-config libcairo2 libcairo2-dev build-essential


ENV ROOT=/stable-diffusion-webui-forge

WORKDIR /
RUN --mount=type=cache,target=/root/.cache/pip \
git clone https://github.com/lllyasviel/stable-diffusion-webui-forge.git && \
cd $ROOT && \
pip install -r requirements_versions.txt

RUN pip install -U typing_extensions

COPY --from=download /repositories/ ${ROOT}/repositories/
RUN mkdir ${ROOT}/interrogate && cp ${ROOT}/repositories/clip-interrogator/clip_interrogator/data/* ${ROOT}/interrogate

RUN --mount=type=cache,target=/root/.cache/pip \
pip install pyngrok xformers==0.0.27 \
git+https://github.com/TencentARC/GFPGAN.git@8d2447a2d918f8eba5a4a01463fd48e45126a379 \
git+https://github.com/openai/CLIP.git@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1 \
git+https://github.com/mlfoundations/[email protected]

# there seems to be a memory leak (or maybe just memory not being freed fast enough) that is fixed by this version of malloc
# maybe move this up to the dependencies list.
RUN apt-get -y install libgoogle-perftools-dev && apt-get clean
ENV LD_PRELOAD=libtcmalloc.so

COPY . /docker

#RUN \
# mv ${ROOT}/style.css ${ROOT}/user.css && \
# one of the ugliest hacks I ever wrote \
#sed -i 's/in_app_dir = .*/in_app_dir = True/g' /opt/conda/lib/python3.10/site-packages/gradio/routes.py && \
#git config --global --add safe.directory '*'

WORKDIR ${ROOT}
ENV NVIDIA_VISIBLE_DEVICES=all
ENV CLI_ARGS=""
EXPOSE 7860
ENTRYPOINT ["/docker/entrypoint.sh"]
CMD python -u webui.py --listen --port 7860 ${CLI_ARGS}
15 changes: 15 additions & 0 deletions services/AUTOMATIC1111-forge/clone.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash

set -Eeox pipefail

mkdir -p /repositories/"$1"
cd /repositories/"$1"
git init
git remote add origin "$2"

if [ -n "$3" ]; then
git fetch origin "$3" --depth=1
git reset --hard "$3"
fi

rm -rf .git
78 changes: 78 additions & 0 deletions services/AUTOMATIC1111-forge/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env python3

"""Checks and sets default values for config.json before starting the container."""

import json
import re
import os.path
import sys

DEFAULT_FILEPATH = '/data/config/forge/config.json'

DEFAULT_OUTDIRS = {
"outdir_samples": "",
"outdir_txt2img_samples": "/output/txt2img",
"outdir_img2img_samples": "/output/img2img",
"outdir_extras_samples": "/output/extras",
"outdir_grids": "",
"outdir_txt2img_grids": "/output/txt2img-grids",
"outdir_img2img_grids": "/output/img2img-grids",
"outdir_save": "/output/saved",
"outdir_init_images": "/output/init-images",
}
RE_VALID_OUTDIR = re.compile(r"(^/output(/\.?[\w\-\_]+)+/?$)|(^\s?$)")

DEFAULT_OTHER = {
"font": "DejaVuSans.ttf",
}

def dict_to_json_file(target_file: str, data: dict):
"""Write dictionary to specified json file"""

with open(target_file, 'w') as f:
json.dump(data, f)

def json_file_to_dict(config_file: str) -> dict|None:
"""Load json file into a dictionary. Return None if file does not exist."""

if os.path.isfile(config_file):
with open(config_file, 'r') as f:
return json.load(f)
else:
return None

def replace_if_invalid(value: str, replacement: str, pattern: str|re.Pattern[str]) -> str:
"""Returns original value if valid, fallback value if invalid"""

if re.match(pattern, value):
return value
else:
return replacement

def check_and_replace_config(config_file: str, target_file: str = None):
"""Checks given file for invalid values. Replaces those with fallback values (default: overwrites file)."""

# Get current user config, or empty if file does not exists
data = json_file_to_dict(config_file) or {}

# Check and fix output directories
for k, def_val in DEFAULT_OUTDIRS.items():
if k not in data:
data[k] = def_val
else:
data[k] = replace_if_invalid(value=data[k], replacement=def_val, pattern=RE_VALID_OUTDIR)

# Check and fix other default settings
for k, def_val in DEFAULT_OTHER.items():
if k not in data:
data[k] = def_val

# Write results to file
dict_to_json_file(target_file or config_file, data)

if __name__ == '__main__':
if len(sys.argv) > 1:
check_and_replace_config(*sys.argv[1:])
else:
check_and_replace_config(DEFAULT_FILEPATH)

85 changes: 85 additions & 0 deletions services/AUTOMATIC1111-forge/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/bin/bash

set -Eeuo pipefail

# TODO: move all mkdir -p ?
mkdir -p /data/config/forge/scripts/
# mount scripts individually

echo $ROOT
ls -lha $ROOT

find "${ROOT}/scripts/" -maxdepth 1 -type l -delete
cp -vrfTs /data/config/forge/scripts/ "${ROOT}/scripts/"

# Set up config file
python /docker/config.py /data/config/forge/config.json

if [ ! -f /data/config/forge/ui-config.json ]; then
echo '{}' >/data/config/forge/ui-config.json
fi

if [ ! -f /data/config/forge/styles.csv ]; then
touch /data/config/forge/styles.csv
fi

# copy models from original models folder
mkdir -p /data/models/VAE-approx/ /data/models/karlo/

rsync -a --info=NAME ${ROOT}/models/VAE-approx/ /data/models/VAE-approx/
rsync -a --info=NAME ${ROOT}/models/karlo/ /data/models/karlo/

declare -A MOUNTS

MOUNTS["/root/.cache"]="/data/.cache"
MOUNTS["${ROOT}/models"]="/data/models"

MOUNTS["${ROOT}/embeddings"]="/data/embeddings"
MOUNTS["${ROOT}/config.json"]="/data/config/forge/config.json"
MOUNTS["${ROOT}/ui-config.json"]="/data/config/forge/ui-config.json"
MOUNTS["${ROOT}/styles.csv"]="/data/config/forge/styles.csv"
MOUNTS["${ROOT}/extensions"]="/data/config/forge/extensions"
MOUNTS["${ROOT}/config_states"]="/data/config/forge/config_states"

# extra hacks
MOUNTS["${ROOT}/repositories/CodeFormer/weights/facelib"]="/data/.cache"

for to_path in "${!MOUNTS[@]}"; do
set -Eeuo pipefail
from_path="${MOUNTS[${to_path}]}"
rm -rf "${to_path}"
if [ ! -f "$from_path" ]; then
mkdir -vp "$from_path"
fi
mkdir -vp "$(dirname "${to_path}")"
ln -sT "${from_path}" "${to_path}"
echo Mounted $(basename "${from_path}")
done

echo "Installing extension dependencies (if any)"

# because we build our container as root:
chown -R root ~/.cache/
chmod 766 ~/.cache/

shopt -s nullglob
# For install.py, please refer to https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Developing-extensions#installpy
list=(./extensions/*/install.py)
for installscript in "${list[@]}"; do
EXTNAME=$(echo $installscript | cut -d '/' -f 3)
# Skip installing dependencies if extension is disabled in config
if $(jq -e ".disabled_extensions|any(. == \"$EXTNAME\")" config.json); then
echo "Skipping disabled extension ($EXTNAME)"
continue
fi
PYTHONPATH=${ROOT} python "$installscript"
done

if [ -f "/data/config/forge/startup.sh" ]; then
pushd ${ROOT}
echo "Running startup script"
. /data/config/forge/startup.sh
popd
fi

exec "$@"
3 changes: 2 additions & 1 deletion services/AUTOMATIC1111/Dockerfile
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ WORKDIR /
RUN --mount=type=cache,target=/root/.cache/pip \
git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git && \
cd stable-diffusion-webui && \
git reset --hard v1.9.4 && \
git reset --hard v1.10.1 && \
pip install -r requirements_versions.txt

RUN pip install -U typing_extensions

ENV ROOT=/stable-diffusion-webui

Expand Down
10 changes: 7 additions & 3 deletions services/AUTOMATIC1111/clone.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
#!/bin/bash

set -Eeuox pipefail
set -Eeox pipefail

mkdir -p /repositories/"$1"
cd /repositories/"$1"
git init
git remote add origin "$2"
git fetch origin "$3" --depth=1
git reset --hard "$3"

if [ -n "$3" ]; then
git fetch origin "$3" --depth=1
git reset --hard "$3"
fi

rm -rf .git
Empty file modified services/AUTOMATIC1111/config.py
100644 → 100755
Empty file.
3 changes: 1 addition & 2 deletions services/comfy/Dockerfile
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM pytorch/pytorch:2.3.0-cuda12.1-cudnn8-runtime
FROM pytorch/pytorch:2.5.1-cuda12.4-cudnn9-runtime

ENV DEBIAN_FRONTEND=noninteractive PIP_PREFER_BINARY=1

Expand All @@ -9,7 +9,6 @@ RUN --mount=type=cache,target=/root/.cache/pip \
git clone https://github.com/comfyanonymous/ComfyUI.git ${ROOT} && \
cd ${ROOT} && \
git checkout master && \
git reset --hard 276f8fce9f5a80b500947fb5745a4dde9e84622d && \
pip install -r requirements.txt

WORKDIR ${ROOT}
Expand Down
Empty file modified services/comfy/extra_model_paths.yaml
100644 → 100755
Empty file.
Empty file modified services/download/Dockerfile
100644 → 100755
Empty file.
Empty file modified services/download/checksums.sha256
100644 → 100755
Empty file.
Empty file modified services/download/links.txt
100644 → 100755
Empty file.