Merge branch 'main' into feat/ip-adapter

This commit is contained in:
psychedelicious 2023-09-02 11:31:08 +10:00 committed by GitHub
commit b761807219
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 750 additions and 750 deletions

View File

@ -46,6 +46,7 @@ if [[ $(python -c 'from importlib.util import find_spec; print(find_spec("build"
pip install --user build pip install --user build
fi fi
rm -r ../build
python -m build --wheel --outdir dist/ ../. python -m build --wheel --outdir dist/ ../.
# ---------------------- # ----------------------

View File

@ -302,6 +302,29 @@ class SDXLCompelPromptInvocation(BaseInvocation, SDXLPromptInvocationBase):
add_time_ids = torch.tensor([original_size + crop_coords + target_size]) add_time_ids = torch.tensor([original_size + crop_coords + target_size])
# [1, 77, 768], [1, 154, 1280]
if c1.shape[1] < c2.shape[1]:
c1 = torch.cat(
[
c1,
torch.zeros(
(c1.shape[0], c2.shape[1] - c1.shape[1], c1.shape[2]), device=c1.device, dtype=c1.dtype
),
],
dim=1,
)
elif c1.shape[1] > c2.shape[1]:
c2 = torch.cat(
[
c2,
torch.zeros(
(c2.shape[0], c1.shape[1] - c2.shape[1], c2.shape[2]), device=c2.device, dtype=c2.dtype
),
],
dim=1,
)
conditioning_data = ConditioningFieldData( conditioning_data = ConditioningFieldData(
conditionings=[ conditionings=[
SDXLConditioningInfo( SDXLConditioningInfo(

View File

@ -464,8 +464,14 @@ class DenoiseLatentsInvocation(BaseInvocation):
latents = context.services.latents.get(self.latents.latents_name) latents = context.services.latents.get(self.latents.latents_name)
if seed is None: if seed is None:
seed = self.latents.seed seed = self.latents.seed
else:
if noise is not None and noise.shape[1:] != latents.shape[1:]:
raise Exception(f"Incompatable 'noise' and 'latents' shapes: {latents.shape=} {noise.shape=}")
elif noise is not None:
latents = torch.zeros_like(noise) latents = torch.zeros_like(noise)
else:
raise Exception("'latents' or 'noise' must be provided!")
if seed is None: if seed is None:
seed = 0 seed = 0

View File

@ -249,7 +249,7 @@ class SDXLLoraLoaderInvocation(BaseInvocation):
"""Apply selected lora to unet and text_encoder.""" """Apply selected lora to unet and text_encoder."""
lora: LoRAModelField = InputField(description=FieldDescriptions.lora_model, input=Input.Direct, title="LoRA") lora: LoRAModelField = InputField(description=FieldDescriptions.lora_model, input=Input.Direct, title="LoRA")
weight: float = Field(default=0.75, description=FieldDescriptions.lora_weight) weight: float = InputField(default=0.75, description=FieldDescriptions.lora_weight)
unet: Optional[UNetField] = Field( unet: Optional[UNetField] = Field(
default=None, description=FieldDescriptions.unet, input=Input.Connection, title="UNET" default=None, description=FieldDescriptions.unet, input=Input.Connection, title="UNET"
) )

View File

@ -109,7 +109,7 @@ class IntegerCollectionInvocation(BaseInvocation):
"""A collection of integer primitive values""" """A collection of integer primitive values"""
collection: list[int] = InputField( collection: list[int] = InputField(
default=0, description="The collection of integer values", ui_type=UIType.IntegerCollection default_factory=list, description="The collection of integer values", ui_type=UIType.IntegerCollection
) )
def invoke(self, context: InvocationContext) -> IntegerCollectionOutput: def invoke(self, context: InvocationContext) -> IntegerCollectionOutput:
@ -261,7 +261,7 @@ class ImageCollectionInvocation(BaseInvocation):
"""A collection of image primitive values""" """A collection of image primitive values"""
collection: list[ImageField] = InputField( collection: list[ImageField] = InputField(
default=0, description="The collection of image values", ui_type=UIType.ImageCollection default_factory=list, description="The collection of image values", ui_type=UIType.ImageCollection
) )
def invoke(self, context: InvocationContext) -> ImageCollectionOutput: def invoke(self, context: InvocationContext) -> ImageCollectionOutput:
@ -451,7 +451,9 @@ class ConditioningCollectionInvocation(BaseInvocation):
"""A collection of conditioning tensor primitive values""" """A collection of conditioning tensor primitive values"""
collection: list[ConditioningField] = InputField( collection: list[ConditioningField] = InputField(
default=0, description="The collection of conditioning tensors", ui_type=UIType.ConditioningCollection default_factory=list,
description="The collection of conditioning tensors",
ui_type=UIType.ConditioningCollection,
) )
def invoke(self, context: InvocationContext) -> ConditioningCollectionOutput: def invoke(self, context: InvocationContext) -> ConditioningCollectionOutput:

View File

@ -6,3 +6,4 @@ from .invokeai_config import ( # noqa F401
InvokeAIAppConfig, InvokeAIAppConfig,
get_invokeai_config, get_invokeai_config,
) )
from .base import PagingArgumentParser # noqa F401

View File

@ -492,10 +492,10 @@ def _parse_legacy_yamlfile(root: Path, initfile: Path) -> ModelPaths:
loras = paths.get("lora_dir", "loras") loras = paths.get("lora_dir", "loras")
controlnets = paths.get("controlnet_dir", "controlnets") controlnets = paths.get("controlnet_dir", "controlnets")
return ModelPaths( return ModelPaths(
models=root / models, models=root / models if models else None,
embeddings=root / embeddings, embeddings=root / embeddings if embeddings else None,
loras=root / loras, loras=root / loras if loras else None,
controlnets=root / controlnets, controlnets=root / controlnets if controlnets else None,
) )

View File

@ -1,7 +1,7 @@
import math import math
import torch
import diffusers
import diffusers
import torch
if torch.backends.mps.is_available(): if torch.backends.mps.is_available():
torch.empty = torch.zeros torch.empty = torch.zeros

View File

@ -4,14 +4,14 @@ sd-1/main/stable-diffusion-v1-5:
repo_id: runwayml/stable-diffusion-v1-5 repo_id: runwayml/stable-diffusion-v1-5
recommended: True recommended: True
default: True default: True
sd-1/main/stable-diffusion-inpainting: sd-1/main/stable-diffusion-v1-5-inpainting:
description: RunwayML SD 1.5 model optimized for inpainting, diffusers version (4.27 GB) description: RunwayML SD 1.5 model optimized for inpainting, diffusers version (4.27 GB)
repo_id: runwayml/stable-diffusion-inpainting repo_id: runwayml/stable-diffusion-inpainting
recommended: True recommended: True
sd-2/main/stable-diffusion-2-1: sd-2/main/stable-diffusion-2-1:
description: Stable Diffusion version 2.1 diffusers model, trained on 768 pixel images (5.21 GB) description: Stable Diffusion version 2.1 diffusers model, trained on 768 pixel images (5.21 GB)
repo_id: stabilityai/stable-diffusion-2-1 repo_id: stabilityai/stable-diffusion-2-1
recommended: True recommended: False
sd-2/main/stable-diffusion-2-inpainting: sd-2/main/stable-diffusion-2-inpainting:
description: Stable Diffusion version 2.0 inpainting model (5.21 GB) description: Stable Diffusion version 2.0 inpainting model (5.21 GB)
repo_id: stabilityai/stable-diffusion-2-inpainting repo_id: stabilityai/stable-diffusion-2-inpainting
@ -19,19 +19,19 @@ sd-2/main/stable-diffusion-2-inpainting:
sdxl/main/stable-diffusion-xl-base-1-0: sdxl/main/stable-diffusion-xl-base-1-0:
description: Stable Diffusion XL base model (12 GB) description: Stable Diffusion XL base model (12 GB)
repo_id: stabilityai/stable-diffusion-xl-base-1.0 repo_id: stabilityai/stable-diffusion-xl-base-1.0
recommended: False recommended: True
sdxl-refiner/main/stable-diffusion-xl-refiner-1-0: sdxl-refiner/main/stable-diffusion-xl-refiner-1-0:
description: Stable Diffusion XL refiner model (12 GB) description: Stable Diffusion XL refiner model (12 GB)
repo_id: stabilityai/stable-diffusion-xl-refiner-1.0 repo_id: stabilityai/stable-diffusion-xl-refiner-1.0
recommended: false recommended: False
sdxl/vae/sdxl-1-0-vae-fix: sdxl/vae/sdxl-1-0-vae-fix:
description: Fine tuned version of the SDXL-1.0 VAE description: Fine tuned version of the SDXL-1.0 VAE
repo_id: madebyollin/sdxl-vae-fp16-fix repo_id: madebyollin/sdxl-vae-fp16-fix
recommended: true recommended: True
sd-1/main/Analog-Diffusion: sd-1/main/Analog-Diffusion:
description: An SD-1.5 model trained on diverse analog photographs (2.13 GB) description: An SD-1.5 model trained on diverse analog photographs (2.13 GB)
repo_id: wavymulder/Analog-Diffusion repo_id: wavymulder/Analog-Diffusion
recommended: false recommended: False
sd-1/main/Deliberate: sd-1/main/Deliberate:
description: Versatile model that produces detailed images up to 768px (4.27 GB) description: Versatile model that produces detailed images up to 768px (4.27 GB)
repo_id: XpucT/Deliberate repo_id: XpucT/Deliberate

View File

@ -60,7 +60,7 @@ class Config:
thumbnail_path = None thumbnail_path = None
def find_and_load(self): def find_and_load(self):
"""find the yaml config file and load""" """Find the yaml config file and load"""
root = app_config.root_path root = app_config.root_path
if not self.confirm_and_load(os.path.abspath(root)): if not self.confirm_and_load(os.path.abspath(root)):
print("\r\nSpecify custom database and outputs paths:") print("\r\nSpecify custom database and outputs paths:")
@ -70,7 +70,7 @@ class Config:
self.thumbnail_path = os.path.join(self.outputs_path, "thumbnails") self.thumbnail_path = os.path.join(self.outputs_path, "thumbnails")
def confirm_and_load(self, invoke_root): def confirm_and_load(self, invoke_root):
"""Validates a yaml path exists, confirms the user wants to use it and loads config.""" """Validate a yaml path exists, confirms the user wants to use it and loads config."""
yaml_path = os.path.join(invoke_root, self.YAML_FILENAME) yaml_path = os.path.join(invoke_root, self.YAML_FILENAME)
if os.path.exists(yaml_path): if os.path.exists(yaml_path):
db_dir, outdir = self.load_paths_from_yaml(yaml_path) db_dir, outdir = self.load_paths_from_yaml(yaml_path)
@ -337,33 +337,24 @@ class InvokeAIMetadataParser:
def map_scheduler(self, old_scheduler): def map_scheduler(self, old_scheduler):
"""Convert the legacy sampler names to matching 3.0 schedulers""" """Convert the legacy sampler names to matching 3.0 schedulers"""
# this was more elegant as a case statement, but that's not available in python 3.9
if old_scheduler is None: if old_scheduler is None:
return None return None
scheduler_map = dict(
match (old_scheduler): ddim="ddim",
case "ddim": plms="pnmd",
return "ddim" k_lms="lms",
case "plms": k_dpm_2="kdpm_2",
return "pnmd" k_dpm_2_a="kdpm_2_a",
case "k_lms": dpmpp_2="dpmpp_2s",
return "lms" k_dpmpp_2="dpmpp_2m",
case "k_dpm_2": k_dpmpp_2_a=None, # invalid, in 2.3.x, selecting this sample would just fallback to last run or plms if new session
return "kdpm_2" k_euler="euler",
case "k_dpm_2_a": k_euler_a="euler_a",
return "kdpm_2_a" k_heun="heun",
case "dpmpp_2": )
return "dpmpp_2s" return scheduler_map.get(old_scheduler)
case "k_dpmpp_2":
return "dpmpp_2m"
case "k_dpmpp_2_a":
return None # invalid, in 2.3.x, selecting this sample would just fallback to last run or plms if new session
case "k_euler":
return "euler"
case "k_euler_a":
return "euler_a"
case "k_heun":
return "heun"
return None
def split_prompt(self, raw_prompt: str): def split_prompt(self, raw_prompt: str):
"""Split the unified prompt strings by extracting all negative prompt blocks out into the negative prompt.""" """Split the unified prompt strings by extracting all negative prompt blocks out into the negative prompt."""
@ -524,27 +515,27 @@ class MediaImportProcessor:
"5) Create/add to board named 'IMPORT' with a the original file app_version appended (.e.g IMPORT_2.2.5)." "5) Create/add to board named 'IMPORT' with a the original file app_version appended (.e.g IMPORT_2.2.5)."
) )
input_option = input("Specify desired board option: ") input_option = input("Specify desired board option: ")
match (input_option): # This was more elegant as a case statement, but not supported in python 3.9
case "1": if input_option == "1":
if len(board_names) < 1: if len(board_names) < 1:
print("\r\nThere are no existing board names to choose from. Select another option!") print("\r\nThere are no existing board names to choose from. Select another option!")
continue continue
board_name = self.select_item_from_list( board_name = self.select_item_from_list(
board_names, "board name", True, "Cancel, go back and choose a different board option." board_names, "board name", True, "Cancel, go back and choose a different board option."
) )
if board_name is not None: if board_name is not None:
return board_name
elif input_option == "2":
while True:
board_name = input("Specify new/existing board name: ")
if board_name:
return board_name return board_name
case "2": elif input_option == "3":
while True: return "IMPORT"
board_name = input("Specify new/existing board name: ") elif input_option == "4":
if board_name: return f"IMPORT_{timestamp_string}"
return board_name elif input_option == "5":
case "3": return "IMPORT_APPVERSION"
return "IMPORT"
case "4":
return f"IMPORT_{timestamp_string}"
case "5":
return "IMPORT_APPVERSION"
def select_item_from_list(self, items, entity_name, allow_cancel, cancel_string): def select_item_from_list(self, items, entity_name, allow_cancel, cancel_string):
"""A general function to render a list of items to select in the console, prompt the user for a selection and ensure a valid entry is selected.""" """A general function to render a list of items to select in the console, prompt the user for a selection and ensure a valid entry is selected."""

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-cyrillic-ext-wght-normal-848492d3.woff2) format("woff2-variations");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-cyrillic-wght-normal-262a1054.woff2) format("woff2-variations");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-greek-ext-wght-normal-fe977ddb.woff2) format("woff2-variations");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-greek-wght-normal-89b4a3fe.woff2) format("woff2-variations");unicode-range:U+0370-03FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-vietnamese-wght-normal-ac4e131c.woff2) format("woff2-variations");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-latin-ext-wght-normal-45606f83.woff2) format("woff2-variations");unicode-range:U+0100-02AF,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-latin-wght-normal-450f3ba4.woff2) format("woff2-variations");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}/*! @font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-cyrillic-ext-wght-normal-848492d3.woff2) format("woff2-variations");unicode-range:U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-cyrillic-wght-normal-262a1054.woff2) format("woff2-variations");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-greek-ext-wght-normal-fe977ddb.woff2) format("woff2-variations");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-greek-wght-normal-89b4a3fe.woff2) format("woff2-variations");unicode-range:U+0370-03FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-vietnamese-wght-normal-ac4e131c.woff2) format("woff2-variations");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-latin-ext-wght-normal-45606f83.woff2) format("woff2-variations");unicode-range:U+0100-02AF,U+0304,U+0308,U+0329,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-latin-wght-normal-450f3ba4.woff2) format("woff2-variations");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}/*!
* OverlayScrollbars * OverlayScrollbars
* Version: 2.2.1 * Version: 2.2.1
* *

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -12,7 +12,7 @@
margin: 0; margin: 0;
} }
</style> </style>
<script type="module" crossorigin src="./assets/index-2c171c8f.js"></script> <script type="module" crossorigin src="./assets/index-08cda350.js"></script>
</head> </head>
<body dir="ltr"> <body dir="ltr">

View File

@ -19,7 +19,7 @@
"toggleAutoscroll": "Toggle autoscroll", "toggleAutoscroll": "Toggle autoscroll",
"toggleLogViewer": "Toggle Log Viewer", "toggleLogViewer": "Toggle Log Viewer",
"showGallery": "Show Gallery", "showGallery": "Show Gallery",
"showOptionsPanel": "Show Options Panel", "showOptionsPanel": "Show Side Panel",
"menu": "Menu" "menu": "Menu"
}, },
"common": { "common": {
@ -52,7 +52,7 @@
"img2img": "Image To Image", "img2img": "Image To Image",
"unifiedCanvas": "Unified Canvas", "unifiedCanvas": "Unified Canvas",
"linear": "Linear", "linear": "Linear",
"nodes": "Node Editor", "nodes": "Workflow Editor",
"batch": "Batch Manager", "batch": "Batch Manager",
"modelManager": "Model Manager", "modelManager": "Model Manager",
"postprocessing": "Post Processing", "postprocessing": "Post Processing",
@ -95,7 +95,6 @@
"statusModelConverted": "Model Converted", "statusModelConverted": "Model Converted",
"statusMergingModels": "Merging Models", "statusMergingModels": "Merging Models",
"statusMergedModels": "Models Merged", "statusMergedModels": "Models Merged",
"pinOptionsPanel": "Pin Options Panel",
"loading": "Loading", "loading": "Loading",
"loadingInvokeAI": "Loading Invoke AI", "loadingInvokeAI": "Loading Invoke AI",
"random": "Random", "random": "Random",
@ -116,7 +115,6 @@
"maintainAspectRatio": "Maintain Aspect Ratio", "maintainAspectRatio": "Maintain Aspect Ratio",
"autoSwitchNewImages": "Auto-Switch to New Images", "autoSwitchNewImages": "Auto-Switch to New Images",
"singleColumnLayout": "Single Column Layout", "singleColumnLayout": "Single Column Layout",
"pinGallery": "Pin Gallery",
"allImagesLoaded": "All Images Loaded", "allImagesLoaded": "All Images Loaded",
"loadMore": "Load More", "loadMore": "Load More",
"noImagesInGallery": "No Images to Display", "noImagesInGallery": "No Images to Display",
@ -133,6 +131,7 @@
"generalHotkeys": "General Hotkeys", "generalHotkeys": "General Hotkeys",
"galleryHotkeys": "Gallery Hotkeys", "galleryHotkeys": "Gallery Hotkeys",
"unifiedCanvasHotkeys": "Unified Canvas Hotkeys", "unifiedCanvasHotkeys": "Unified Canvas Hotkeys",
"nodesHotkeys": "Nodes Hotkeys",
"invoke": { "invoke": {
"title": "Invoke", "title": "Invoke",
"desc": "Generate an image" "desc": "Generate an image"
@ -332,6 +331,10 @@
"acceptStagingImage": { "acceptStagingImage": {
"title": "Accept Staging Image", "title": "Accept Staging Image",
"desc": "Accept Current Staging Area Image" "desc": "Accept Current Staging Area Image"
},
"addNodes": {
"title": "Add Nodes",
"desc": "Opens the add node menu"
} }
}, },
"modelManager": { "modelManager": {
@ -503,13 +506,15 @@
"hiresStrength": "High Res Strength", "hiresStrength": "High Res Strength",
"imageFit": "Fit Initial Image To Output Size", "imageFit": "Fit Initial Image To Output Size",
"codeformerFidelity": "Fidelity", "codeformerFidelity": "Fidelity",
"compositingSettingsHeader": "Compositing Settings",
"maskAdjustmentsHeader": "Mask Adjustments", "maskAdjustmentsHeader": "Mask Adjustments",
"maskBlur": "Mask Blur", "maskBlur": "Blur",
"maskBlurMethod": "Mask Blur Method", "maskBlurMethod": "Blur Method",
"seamSize": "Seam Size", "coherencePassHeader": "Coherence Pass",
"seamBlur": "Seam Blur", "coherenceSteps": "Steps",
"seamStrength": "Seam Strength", "coherenceStrength": "Strength",
"seamSteps": "Seam Steps", "seamLowThreshold": "Low",
"seamHighThreshold": "High",
"scaleBeforeProcessing": "Scale Before Processing", "scaleBeforeProcessing": "Scale Before Processing",
"scaledWidth": "Scaled W", "scaledWidth": "Scaled W",
"scaledHeight": "Scaled H", "scaledHeight": "Scaled H",
@ -565,10 +570,11 @@
"useSlidersForAll": "Use Sliders For All Options", "useSlidersForAll": "Use Sliders For All Options",
"showProgressInViewer": "Show Progress Images in Viewer", "showProgressInViewer": "Show Progress Images in Viewer",
"antialiasProgressImages": "Antialias Progress Images", "antialiasProgressImages": "Antialias Progress Images",
"autoChangeDimensions": "Update W/H To Model Defaults On Change",
"resetWebUI": "Reset Web UI", "resetWebUI": "Reset Web UI",
"resetWebUIDesc1": "Resetting the web UI only resets the browser's local cache of your images and remembered settings. It does not delete any images from disk.", "resetWebUIDesc1": "Resetting the web UI only resets the browser's local cache of your images and remembered settings. It does not delete any images from disk.",
"resetWebUIDesc2": "If images aren't showing up in the gallery or something else isn't working, please try resetting before submitting an issue on GitHub.", "resetWebUIDesc2": "If images aren't showing up in the gallery or something else isn't working, please try resetting before submitting an issue on GitHub.",
"resetComplete": "Web UI has been reset. Refresh the page to reload.", "resetComplete": "Web UI has been reset.",
"consoleLogLevel": "Log Level", "consoleLogLevel": "Log Level",
"shouldLogToConsole": "Console Logging", "shouldLogToConsole": "Console Logging",
"developer": "Developer", "developer": "Developer",
@ -708,14 +714,16 @@
"ui": { "ui": {
"showProgressImages": "Show Progress Images", "showProgressImages": "Show Progress Images",
"hideProgressImages": "Hide Progress Images", "hideProgressImages": "Hide Progress Images",
"swapSizes": "Swap Sizes" "swapSizes": "Swap Sizes",
"lockRatio": "Lock Ratio"
}, },
"nodes": { "nodes": {
"reloadSchema": "Reload Schema", "reloadNodeTemplates": "Reload Node Templates",
"saveGraph": "Save Graph", "downloadWorkflow": "Download Workflow JSON",
"loadGraph": "Load Graph (saved from Node Editor) (Do not copy-paste metadata)", "loadWorkflow": "Load Workflow",
"clearGraph": "Clear Graph", "resetWorkflow": "Reset Workflow",
"clearGraphDesc": "Are you sure you want to clear all nodes?", "resetWorkflowDesc": "Are you sure you want to reset this workflow?",
"resetWorkflowDesc2": "Resetting the workflow will clear all nodes, edges and workflow details.",
"zoomInNodes": "Zoom In", "zoomInNodes": "Zoom In",
"zoomOutNodes": "Zoom Out", "zoomOutNodes": "Zoom Out",
"fitViewportNodes": "Fit View", "fitViewportNodes": "Fit View",

View File

@ -104,22 +104,22 @@ const ControlNetImagePreview = ({ isSmall, controlNet }: Props) => {
]); ]);
const handleSetControlImageToDimensions = useCallback(() => { const handleSetControlImageToDimensions = useCallback(() => {
if (!processedControlImage) { if (!controlImage) {
return; return;
} }
if (activeTabName === 'unifiedCanvas') { if (activeTabName === 'unifiedCanvas') {
dispatch( dispatch(
setBoundingBoxDimensions({ setBoundingBoxDimensions({
width: processedControlImage.width, width: controlImage.width,
height: processedControlImage.height, height: controlImage.height,
}) })
); );
} else { } else {
dispatch(setWidth(processedControlImage.width)); dispatch(setWidth(controlImage.width));
dispatch(setHeight(processedControlImage.height)); dispatch(setHeight(controlImage.height));
} }
}, [processedControlImage, activeTabName, dispatch]); }, [controlImage, activeTabName, dispatch]);
const handleMouseEnter = useCallback(() => { const handleMouseEnter = useCallback(() => {
setIsMouseOverImage(true); setIsMouseOverImage(true);

View File

@ -1,4 +1,3 @@
import { store } from 'app/store/store';
import { import {
SchedulerParam, SchedulerParam,
zBaseModel, zBaseModel,
@ -10,7 +9,6 @@ import { keyBy } from 'lodash-es';
import { OpenAPIV3 } from 'openapi-types'; import { OpenAPIV3 } from 'openapi-types';
import { RgbaColor } from 'react-colorful'; import { RgbaColor } from 'react-colorful';
import { Node } from 'reactflow'; import { Node } from 'reactflow';
import { JsonObject } from 'type-fest';
import { Graph, ImageDTO, _InputField, _OutputField } from 'services/api/types'; import { Graph, ImageDTO, _InputField, _OutputField } from 'services/api/types';
import { import {
AnyInvocationType, AnyInvocationType,
@ -18,6 +16,7 @@ import {
ProgressImage, ProgressImage,
} from 'services/events/types'; } from 'services/events/types';
import { O } from 'ts-toolbelt'; import { O } from 'ts-toolbelt';
import { JsonObject } from 'type-fest';
import { z } from 'zod'; import { z } from 'zod';
export type NonNullableGraph = O.Required<Graph, 'nodes' | 'edges'>; export type NonNullableGraph = O.Required<Graph, 'nodes' | 'edges'>;
@ -280,7 +279,7 @@ export type ConditioningInputFieldValue = z.infer<
export const zControlNetModel = zModelIdentifier; export const zControlNetModel = zModelIdentifier;
export type ControlNetModel = z.infer<typeof zControlNetModel>; export type ControlNetModel = z.infer<typeof zControlNetModel>;
export const zControlField = zInputFieldValueBase.extend({ export const zControlField = z.object({
image: zImageField, image: zImageField,
control_model: zControlNetModel, control_model: zControlNetModel,
control_weight: z.union([z.number(), z.array(z.number())]).optional(), control_weight: z.union([z.number(), z.array(z.number())]).optional(),
@ -295,11 +294,11 @@ export const zControlField = zInputFieldValueBase.extend({
}); });
export type ControlField = z.infer<typeof zControlField>; export type ControlField = z.infer<typeof zControlField>;
export const zControlInputFieldTemplate = zInputFieldValueBase.extend({ export const zControlInputFieldValue = zInputFieldValueBase.extend({
type: z.literal('ControlField'), type: z.literal('ControlField'),
value: zControlField.optional(), value: zControlField.optional(),
}); });
export type ControlInputFieldValue = z.infer<typeof zControlInputFieldTemplate>; export type ControlInputFieldValue = z.infer<typeof zControlInputFieldValue>;
export const zModelType = z.enum([ export const zModelType = z.enum([
'onnx', 'onnx',
@ -492,7 +491,7 @@ export const zInputFieldValue = z.discriminatedUnion('type', [
zUNetInputFieldValue, zUNetInputFieldValue,
zClipInputFieldValue, zClipInputFieldValue,
zVaeInputFieldValue, zVaeInputFieldValue,
zControlInputFieldTemplate, zControlInputFieldValue,
zEnumInputFieldValue, zEnumInputFieldValue,
zMainModelInputFieldValue, zMainModelInputFieldValue,
zSDXLMainModelInputFieldValue, zSDXLMainModelInputFieldValue,
@ -936,22 +935,10 @@ export const zWorkflow = z.object({
}); });
export const zValidatedWorkflow = zWorkflow.transform((workflow) => { export const zValidatedWorkflow = zWorkflow.transform((workflow) => {
const nodeTemplates = store.getState().nodes.nodeTemplates;
const { nodes, edges } = workflow; const { nodes, edges } = workflow;
const warnings: WorkflowWarning[] = []; const warnings: WorkflowWarning[] = [];
const invocationNodes = nodes.filter(isWorkflowInvocationNode); const invocationNodes = nodes.filter(isWorkflowInvocationNode);
const keyedNodes = keyBy(invocationNodes, 'id'); const keyedNodes = keyBy(invocationNodes, 'id');
invocationNodes.forEach((node, i) => {
const nodeTemplate = nodeTemplates[node.data.type];
if (!nodeTemplate) {
warnings.push({
message: `Node "${node.data.label || node.data.id}" skipped`,
issues: [`Unable to find template for type "${node.data.type}"`],
data: node,
});
delete nodes[i];
}
});
edges.forEach((edge, i) => { edges.forEach((edge, i) => {
const sourceNode = keyedNodes[edge.source]; const sourceNode = keyedNodes[edge.source];
const targetNode = keyedNodes[edge.target]; const targetNode = keyedNodes[edge.target];

View File

@ -12,17 +12,21 @@ export const buildWorkflow = (nodesState: NodesState): Workflow => {
edges: [], edges: [],
}; };
nodes.forEach((node) => { nodes
const result = zWorkflowNode.safeParse(node); .filter((n) =>
if (!result.success) { ['invocation', 'notes'].includes(n.type ?? '__UNKNOWN_NODE_TYPE__')
const { message } = fromZodError(result.error, { )
prefix: 'Unable to parse node', .forEach((node) => {
}); const result = zWorkflowNode.safeParse(node);
logger('nodes').warn({ node: parseify(node) }, message); if (!result.success) {
return; const { message } = fromZodError(result.error, {
} prefix: 'Unable to parse node',
workflow.nodes.push(result.data); });
}); logger('nodes').warn({ node: parseify(node) }, message);
return;
}
workflow.nodes.push(result.data);
});
edges.forEach((edge) => { edges.forEach((edge) => {
const result = zWorkflowEdge.safeParse(edge); const result = zWorkflowEdge.safeParse(edge);

View File

@ -1 +1 @@
__version__ = "3.0.2post1" __version__ = "3.1.0"