Skip to content

Commit 9721810

Browse files
committed
chore: enable juririgged polling for devcontainer support
chore: use container mount path variable instead of hardcoded strings chore: add proper env file initialization for devcontainer chore: explicitly create other cache folders chore remove file so it can be recommitted properly chore: commit init file with executable mode set chore: remove unneeded debug launch target chore: add more recommended extensions chore: remove unneeded git files chore: fix python preinstall chore: update cuda index to match main chore: drop redundant devcontainer specific extensions list and just use global workspace extensions list. refactor: move to hatchling for python compiler-backend chore: oh we actually DO need to specify extensions in the devcontainer.json refactor: enable UV to handle device-specific torch index resolution. chore: whoops, fix the named volume name
1 parent d190a1d commit 9721810

File tree

11 files changed

+1602
-1552
lines changed

11 files changed

+1602
-1552
lines changed

.devcontainer/.vscode/launch.json

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,6 @@
44
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
55
"version": "0.2.0",
66
"configurations": [
7-
{
8-
"name": "InvokeAI :: Chrome",
9-
"type": "chrome",
10-
"request": "launch",
11-
"url": "http://localhost:9090",
12-
"webRoot": "${workspaceFolder}/invokeai/frontend/web"
13-
},
147
{
158
"name": "InvokeAI :: Backend",
169
"type": "debugpy",

.devcontainer/Dockerfile

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ ENV \
3131
UV_PROJECT_ENVIRONMENT=${UV_PROJECT_ENVIRONMENT}
3232

3333
ENV \
34+
COMPUTE_DEVICE=${COMPUTE_DEVICE} \
3435
PYTHONUNBUFFERED=1 \
3536
PYTHONDONTWRITEBYTECODE=1 \
3637
UV_MANAGED_PYTHON=1 \
@@ -39,16 +40,6 @@ ENV \
3940
INVOKEAI_ROOT=${INVOKEAI_ROOT} \
4041
HF_HOME=${HF_HOME}
4142

42-
# Set the secondary index for UV to the appropriate PyTorch index URL based on the GPU driver and architecture
43-
# NOTE: this is the index URL that will be used by `uv` to install PyTorch and other packages
44-
# Instead of using an envar we write the value to the user-level config file for UV
45-
RUN if [ "$TARGETPLATFORM" = "linux/arm64" ] || [ "$COMPUTE_DEVICE" = "cpu" ]; then export UV_INDEX="https://download.pytorch.org/whl/cpu"; \
46-
elif [ "$COMPUTE_DEVICE" = "rocm" ]; then export UV_INDEX="https://download.pytorch.org/whl/rocm6.2"; \
47-
else export UV_INDEX="https://download.pytorch.org/whl/cu124"; \
48-
fi \
49-
&& mkdir -p /home/${USERNAME}/.config/uv/ \
50-
&& echo "[[index]]\nurl = '$(echo $UV_INDEX)'\n" > /home/${USERNAME}/.config/uv/uv.toml
51-
5243
# Set Python version
5344
# NOTE: this is the version of Python that will be installed by `uv`
5445
ARG PYTHON_VERSION=3.12
@@ -60,31 +51,40 @@ UV_PYTHON=${PYTHON_VERSION}
6051
ARG CACHE_DIR=/home/${USERNAME}/.cache
6152
# Setting XDG_CACHE_HOME will affect the location of the cache for pnpm and uv, and possibly other tools
6253
# https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
54+
# We set XDG_DATA_HOME to a non-volume-mounted location to guarantee that UV pre-installs python. (if its mounted it will only be installed after container start)
6355
ENV XDG_CACHE_HOME=${CACHE_DIR} \
56+
XDG_DATA_HOME=/home/${USERNAME}/.data \
6457
GIT_LFS_CACHE=${CACHE_DIR}/git-lfs \
6558
PATH="$UV_PROJECT_ENVIRONMENT/bin:$CACHE_DIR/pnpm:$CACHE_DIR/uv:$PATH" \
6659
PYTHONPATH="$PYTHONPATH:${INVOKEAI_SRC}"
6760

68-
# Setup cache volume for dependencies
69-
VOLUME [ "${CACHE_DIR}", "${INVOKEAI_SRC}", "${HF_HOME}"]
61+
# Predeclare volume mounting points for directories which will be written to.
62+
# This guarantees that even if the devcontainer doesnt mount a volume for these paths, their contents will still be handled by a volume,
63+
# rather than being written to the container image layers itself.
64+
VOLUME [ "${CACHE_DIR}", "${INVOKEAI_SRC}", "${INVOKEAI_ROOT}", "${HF_HOME}"]
7065

7166
# Create & set ownership of directories
7267
RUN set -eux; \
7368
mkdir -p ${CACHE_DIR} && \
7469
mkdir -p ${CACHE_DIR}/uv && \
7570
mkdir -p ${CACHE_DIR}/pnpm && \
71+
mkdir -p ${CACHE_DIR}/node && \
72+
mkdir -p ${CACHE_DIR}/Microsoft && \
7673
mkdir -p ${INVOKEAI_ROOT}/models/.download_cache && \
7774
mkdir -p ${UV_PROJECT_ENVIRONMENT} && \
7875
chown --recursive ${USERNAME}:${USERNAME} ${CACHE_DIR} && \
7976
chown --recursive ${USERNAME}:${USERNAME} ${INVOKEAI_ROOT} && \
80-
chown --recursive ${USERNAME}:${USERNAME} ${UV_PROJECT_ENVIRONMENT}
77+
chown --recursive ${USERNAME}:${USERNAME} ${UV_PROJECT_ENVIRONMENT} && \
78+
mkdir -p /home/${USERNAME}/.data && \
79+
chown --recursive ${USERNAME}:${USERNAME} /home/${USERNAME}/.data
8180

8281
# Setup PNPM
8382
RUN corepack use pnpm && corepack enable
8483

8584
# Install `uv` for package management
8685
COPY --from=ghcr.io/astral-sh/uv:0.6 /uv /uvx /bin/
8786

88-
RUN uv python install ${PYTHON_VERSION}
87+
RUN uv venv && uv python install ${PYTHON_VERSION}
88+
ENV UV_PYTHON_DOWNLOADS=never
8989

9090
WORKDIR ${INVOKEAI_SRC}

.devcontainer/devcontainer.json

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"USERNAME": "node",
88
"PYTHON_VERSION": "3.12", // The python version which will be installed in the container
99
"INVOKEAI_ROOT": "/home/node/invokeai",
10-
"INVOKEAI_SRC": "/workspaces/InvokeAI"
10+
"INVOKEAI_SRC": "${containerWorkspaceFolder}"
1111
}
1212
},
1313
"mounts": [
@@ -38,7 +38,8 @@
3838
],
3939
"containerEnv": {
4040
"UV_COMPILE_BYTECODE": "1",
41-
"INVOKEAI_DEV_RELOAD": "true"
41+
"INVOKEAI_DEV_RELOAD": "true",
42+
"UV_LINK_MODE": "symlink" // Using symlink because they are fast and always work, if you encounter issues after a cache purge, just rebuild the container.
4243
},
4344
"features": {
4445
"ghcr.io/devcontainers/features/git-lfs": {},
@@ -48,19 +49,18 @@
4849
"gpu": "optional"
4950
},
5051
"runArgs": ["--env-file", ".devcontainer/.env"],
52+
"initializeCommand": [".devcontainer/scripts/init"],
5153
"onCreateCommand": "pnpm config --global set store-dir $XDG_CACHE_HOME/pnpm",
52-
"updateContentCommand": {
53-
"Frontend::Setup": "pnpm install --dir invokeai/frontend/web --reporter append-only --prefer-offline",
54-
"Backend::Setup": "uv sync --inexact --all-extras --no-extra onnx-directml"
55-
},
54+
"updateContentCommand": "pnpm install --dir invokeai/frontend/web --prefer-offline",
55+
"postAttachCommand": "uv sync --extra using-$(echo ${COMPUTE_DEVICE:-cpu}) --extra dev --extra test --extra docs",
5656
"customizations": {
5757
"vscode": {
5858
"settings": {
5959
"python.defaultInterpreterPath": "/home/node/.venv/bin/python",
6060
"python.analysis.extraPaths": [
61-
"/invokeai",
62-
"/workspaces/InvokeAI",
63-
"/home/node/.venv/lib"
61+
"/home/node/invokeai",
62+
"/home/node/.venv/lib",
63+
"${containerWorkspaceFolder}"
6464
],
6565
"files.autoSaveWhenNoErrors": true,
6666
"editor.formatOnSave": true,
@@ -70,18 +70,21 @@
7070
"ruff.linting.enabled": true
7171
},
7272
"extensions": [
73-
"eamodio.gitlens",
73+
"ms-vscode-remote.remote-containers",
74+
"ms-azuretools.vscode-docker",
7475
"ms-toolsai.jupyter",
7576
"ms-toolsai.vscode-jupyter-cell-tags",
7677
"ms-toolsai.jupyter-renderers",
7778
"ms-toolsai.vscode-jupyter-slideshow",
79+
"ms-python.python",
7880
"charliermarsh.ruff",
7981
"esbenp.prettier-vscode",
8082
"DavidAnson.vscode-markdownlint",
8183
"antfu.vite",
8284
"docker.docker",
83-
"ms-vscode-remote.remote-containers",
84-
"ms-azuretools.vscode-docker"
85+
"dbaeumer.vscode-eslint",
86+
"vitest.explorer",
87+
"tamasfe.even-better-toml"
8588
]
8689
}
8790
}

.devcontainer/scripts/init

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
touch .env

.devcontainer/scripts/init.cmd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@ECHO off
2+
if not exist .env copy NUL .env

.vscode/extensions.json

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
{
2-
"recommendations": [
3-
"charliermarsh.ruff",
4-
"esbenp.prettier-vscode",
5-
"DavidAnson.vscode-markdownlint",
6-
"antfu.vite",
7-
"docker.docker",
8-
"ms-vscode-remote.remote-containers",
9-
"ms-azuretools.vscode-docker",
10-
"ms-toolsai.jupyter",
11-
"ms-toolsai.vscode-jupyter-cell-tags",
12-
"ms-toolsai.jupyter-renderers",
13-
"ms-toolsai.vscode-jupyter-slideshow",
14-
]
15-
}
2+
"recommendations": [
3+
"ms-vscode-remote.remote-containers",
4+
"ms-azuretools.vscode-docker",
5+
"ms-toolsai.jupyter",
6+
"ms-toolsai.vscode-jupyter-cell-tags",
7+
"ms-toolsai.jupyter-renderers",
8+
"ms-toolsai.vscode-jupyter-slideshow",
9+
"ms-python.python",
10+
"charliermarsh.ruff",
11+
"esbenp.prettier-vscode",
12+
"DavidAnson.vscode-markdownlint",
13+
"antfu.vite",
14+
"docker.docker",
15+
"dbaeumer.vscode-eslint",
16+
"vitest.explorer",
17+
"tamasfe.even-better-toml"
18+
]
19+
}

invokeai/app/invocations/custom_nodes/.gitignore

Lines changed: 0 additions & 1 deletion
This file was deleted.

invokeai/app/invocations/custom_nodes/.gitinclude

Lines changed: 0 additions & 2 deletions
This file was deleted.

invokeai/app/util/startup_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def enable_dev_reload(custom_nodes_path=None) -> None:
5757
paths = [str(invokeai_source_dir() / "*.py")]
5858
if custom_nodes_path:
5959
paths.append(str(custom_nodes_path / "*.py"))
60-
jurigged.watch(pattern=paths, logger=InvokeAILogger.get_logger(name="jurigged").info)
60+
jurigged.watch(pattern=paths, logger=InvokeAILogger.get_logger(name="jurigged").info, poll=True)
6161

6262

6363
def apply_monkeypatches() -> None:

pyproject.toml

Lines changed: 70 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[build-system]
2-
requires = ["setuptools", "pip", "wheel"]
3-
build-backend = "setuptools.build_meta"
2+
requires = ["hatchling>=1.25.0"]
3+
build-backend = "hatchling.build"
44

55
[project]
66
name = "InvokeAI"
@@ -38,20 +38,19 @@ dependencies = [
3838
"compel==2.0.2",
3939
"diffusers[torch]==0.33.0",
4040
"gguf",
41-
"invisible-watermark==0.2.0", # needed to install SDXL base and refiner using their repo_ids
42-
"mediapipe==0.10.14", # needed for "mediapipeface" controlnet model
41+
"invisible-watermark==0.2.0", # needed to install SDXL base and refiner using their repo_ids
42+
"mediapipe==0.10.14", # needed for "mediapipeface" controlnet model
4343
"numpy<2.0.0",
4444
"onnx==1.16.1",
4545
"onnxruntime==1.19.2",
4646
"opencv-python==4.9.0.80",
4747
"safetensors",
4848
"sentencepiece",
4949
"spandrel",
50-
"torch~=2.6.0", # torch and related dependencies are loosely pinned, will respect requirement of `diffusers[torch]`
51-
"torchsde", # diffusers needs this for SDE solvers, but it is not an explicit dep of diffusers
50+
"torch~=2.6.0", # torch and related dependencies are loosely pinned, will respect requirement of `diffusers[torch]`
51+
"torchsde", # diffusers needs this for SDE solvers, but it is not an explicit dep of diffusers
5252
"torchvision",
5353
"transformers",
54-
5554
# Core application dependencies, pinned for reproducible builds.
5655
"fastapi-events",
5756
"fastapi",
@@ -60,7 +59,6 @@ dependencies = [
6059
"pydantic",
6160
"python-socketio",
6261
"uvicorn[standard]",
63-
6462
# Auxiliary dependencies, pinned only if necessary.
6563
"blake3",
6664
"Deprecated",
@@ -82,7 +80,6 @@ dependencies = [
8280
"xformers>=0.0.28.post1; sys_platform!='darwin'",
8381
# torch 2.4+cu carries its own triton dependency
8482
]
85-
8683
"onnx" = ["onnxruntime"]
8784
"onnx-cuda" = ["onnxruntime-gpu"]
8885
"onnx-directml" = ["onnxruntime-directml"]
@@ -108,6 +105,10 @@ dependencies = [
108105
"polyfactory==2.19.0",
109106
"humanize==4.12.1",
110107
]
108+
# Have to declare these here so they are valid values for the `extra` field
109+
"using-cpu" = []
110+
"using-cuda" = ["onnxruntime-gpu"]
111+
"using-rocm" = []
111112

112113
[project.scripts]
113114
"invokeai-web" = "invokeai.app.run_app:run_app"
@@ -119,37 +120,35 @@ dependencies = [
119120
"Bug Reports" = "https://github.com/invoke-ai/InvokeAI/issues"
120121
"Discord" = "https://discord.gg/ZmtBAhwWhy"
121122

122-
[tool.setuptools.dynamic]
123-
version = { attr = "invokeai.version.__version__" }
123+
[tool.hatch.version]
124+
path = "invokeai/version/invokeai_version.py"
125+
attribute = "__version__"
124126

125-
[tool.setuptools.packages.find]
126-
"where" = ["."]
127-
"include" = [
128-
"invokeai.assets.fonts*",
129-
"invokeai.version*",
130-
"invokeai.generator*",
131-
"invokeai.backend*",
132-
"invokeai.frontend*",
133-
"invokeai.frontend.web.dist*",
134-
"invokeai.frontend.web.static*",
135-
"invokeai.configs*",
136-
"invokeai.app*",
137-
"invokeai.invocation_api*",
127+
[tool.hatch.build]
128+
include = [
129+
"invokeai/app/assets/**/*.png",
130+
"invokeai/app/services/workflow_records/default_workflows/*.json",
131+
"invokeai/app/services/style_preset_records/*.json",
132+
"invokeai/app/services/style_preset_images/default_style_preset_images/*.png",
133+
"invokeai/assets/fonts/**/*.ttf",
134+
"invokeai/backend/**/*.png",
135+
"invokeai/configs/*.example",
136+
"invokeai/configs/**/*.yaml",
137+
"invokeai/configs/*.txt",
138+
"invokeai/frontend/web/dist/**",
139+
"invokeai/frontend/web/static/**",
140+
"invokeai/app/invocations/**",
141+
"README.md",
142+
"LICENSE",
138143
]
144+
# exclude = ["tests/**", "docs/**"]
145+
146+
[tool.hatch.build.targets.wheel]
147+
# Wheel gets exactly the same files by default, no extra config needed.
148+
149+
[tool.hatch.build.targets.sdist]
150+
# Sdist will pull in everything under include/exclude.
139151

140-
[tool.setuptools.package-data]
141-
"invokeai.app.assets" = ["**/*.png"]
142-
"invokeai.app.services.workflow_records.default_workflows" = ["*.json"]
143-
"invokeai.app.services.style_preset_records" = ["*.json"]
144-
"invokeai.app.services.style_preset_images.default_style_preset_images" = [
145-
"*.png",
146-
]
147-
"invokeai.assets.fonts" = ["**/*.ttf"]
148-
"invokeai.backend" = ["**.png", "**/*.icc"]
149-
"invokeai.configs" = ["*.example", "**/*.yaml", "*.txt"]
150-
"invokeai.frontend.web.dist" = ["**"]
151-
"invokeai.frontend.web.static" = ["**"]
152-
"invokeai.app.invocations" = ["**"]
153152

154153
#=== Begin: PyTest and Coverage
155154
[tool.pytest.ini_options]
@@ -295,3 +294,37 @@ reportUntypedBaseClass = "warning"
295294
reportUntypedClassDecorator = "warning"
296295
reportUntypedFunctionDecorator = "warning"
297296
reportUntypedNamedTuple = "warning"
297+
298+
#=== Begin: UV
299+
300+
[tool.uv.sources]
301+
torch = [
302+
# { index = "default", marker = "sys_platform == 'darwin'" }, # macOS
303+
{ index = "pytorch-arm", marker = "sys_platform != 'darwin' and platform_machine == 'arm64'" },
304+
# Linux and Windows
305+
{ index = "pytorch-cu126", marker = "sys_platform != 'darwin' and platform_machine == 'x86_64' and extra == 'using-cuda' and extra != 'using-rocm'" },
306+
{ index = "pytorch-rocm", marker = "sys_platform != 'darwin' and platform_machine == 'x86_64' and extra != 'using-cuda' and extra == 'using-rocm'" },
307+
{ index = "pytorch-cpu", marker = "sys_platform != 'darwin' and platform_machine == 'x86_64' and extra != 'using-cuda' and extra != 'using-rocm'" },
308+
]
309+
310+
[[tool.uv.index]]
311+
name = "pytorch-rocm"
312+
url = "https://download.pytorch.org/whl/rocm6.2"
313+
explicit = true
314+
315+
[[tool.uv.index]]
316+
name = "pytorch-cu126"
317+
url = "https://download.pytorch.org/whl/cu126"
318+
explicit = true
319+
320+
[[tool.uv.index]]
321+
name = "pytorch-arm"
322+
url = "https://download.pytorch.org/whl/cpu"
323+
explicit = true
324+
325+
[[tool.uv.index]]
326+
name = "pytorch-cpu"
327+
url = "https://download.pytorch.org/whl/cpu"
328+
explicit = true
329+
330+
#=== End: UV

0 commit comments

Comments
 (0)