diff --git a/docs/nodes/communityNodes.md b/docs/nodes/communityNodes.md index e61c68bf2f..c7456fcd4b 100644 --- a/docs/nodes/communityNodes.md +++ b/docs/nodes/communityNodes.md @@ -41,7 +41,7 @@ To use a community node graph, download the the `.json` node graph file and load **Description:** This InvokeAI node takes in a collection of images and randomly chooses one. This can be useful when you have a number of poses to choose from for a ControlNet node, or a number of input images for another purpose. -**Node Link:** https://github.com/JPPhoto/film-grain-node +**Node Link:** https://github.com/JPPhoto/image-picker-node -------------------------------- ### Retroize diff --git a/invokeai/app/services/graph.py b/invokeai/app/services/graph.py index 0e40636280..c47d437956 100644 --- a/invokeai/app/services/graph.py +++ b/invokeai/app/services/graph.py @@ -182,7 +182,7 @@ class IterateInvocationOutput(BaseInvocationOutput): # TODO: Fill this out and move to invocations -@invocation("iterate") +@invocation("iterate", version="1.0.0") class IterateInvocation(BaseInvocation): """Iterates over a list of items""" @@ -203,7 +203,7 @@ class CollectInvocationOutput(BaseInvocationOutput): ) -@invocation("collect") +@invocation("collect", version="1.0.0") class CollectInvocation(BaseInvocation): """Collects values into a collection""" diff --git a/invokeai/backend/install/invokeai_configure.py b/invokeai/backend/install/invokeai_configure.py index 4a512bfa5f..c5dce13050 100755 --- a/invokeai/backend/install/invokeai_configure.py +++ b/invokeai/backend/install/invokeai_configure.py @@ -507,7 +507,7 @@ Use cursor arrows to make a checkbox selection, and space to toggle. scroll_exit=True, ) else: - self.vram_cache_size = DummyWidgetValue.zero + self.vram = DummyWidgetValue.zero self.nextrely += 1 self.outdir = self.add_widget_intelligent( FileBox, @@ -605,7 +605,8 @@ https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/blob/main/LICENS "vram", "outdir", ]: - setattr(new_opts, attr, getattr(self, attr).value) + if hasattr(self, attr): + setattr(new_opts, attr, getattr(self, attr).value) for attr in self.autoimport_dirs: directory = Path(self.autoimport_dirs[attr].value) diff --git a/invokeai/frontend/install/invokeai_update.py b/invokeai/frontend/install/invokeai_update.py index 3fe9bb6f97..45a0e8ec0a 100644 --- a/invokeai/frontend/install/invokeai_update.py +++ b/invokeai/frontend/install/invokeai_update.py @@ -54,13 +54,15 @@ def welcome(versions: dict): def text(): yield f"InvokeAI Version: [bold yellow]{__version__}" yield "" - yield "This script will update InvokeAI to the latest release, or to a development version of your choice." + yield "This script will update InvokeAI to the latest release, or to the development version of your choice." + yield "" + yield "When updating to an arbitrary tag or branch, be aware that the front end may be mismatched to the backend," + yield "making the web frontend unusable. Please downgrade to the latest release if this happens." yield "" yield "[bold yellow]Options:" yield f"""[1] Update to the latest official release ([italic]{versions[0]['tag_name']}[/italic]) -[2] Update to the bleeding-edge development version ([italic]main[/italic]) -[3] Manually enter the [bold]tag name[/bold] for the version you wish to update to -[4] Manually enter the [bold]branch name[/bold] for the version you wish to update to""" +[2] Manually enter the [bold]tag name[/bold] for the version you wish to update to +[3] Manually enter the [bold]branch name[/bold] for the version you wish to update to""" console.rule() print( @@ -104,11 +106,11 @@ def main(): if choice == "1": release = versions[0]["tag_name"] elif choice == "2": - release = "main" + while not tag: + tag = Prompt.ask("Enter an InvokeAI tag name") elif choice == "3": - tag = Prompt.ask("Enter an InvokeAI tag name") - elif choice == "4": - branch = Prompt.ask("Enter an InvokeAI branch name") + while not branch: + branch = Prompt.ask("Enter an InvokeAI branch name") extras = get_extras() diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts index ca26a0567f..fb908fa601 100644 --- a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts +++ b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts @@ -235,10 +235,18 @@ export const canvasSlice = createSlice({ state.boundingBoxDimensions.width, state.boundingBoxDimensions.height, ]; + const [currScaledWidth, currScaledHeight] = [ + state.scaledBoundingBoxDimensions.width, + state.scaledBoundingBoxDimensions.height, + ]; state.boundingBoxDimensions = { width: currHeight, height: currWidth, }; + state.scaledBoundingBoxDimensions = { + width: currScaledHeight, + height: currScaledWidth, + }; }, setBoundingBoxCoordinates: (state, action: PayloadAction) => { state.boundingBoxCoordinates = floorCoordinates(action.payload); @@ -788,6 +796,10 @@ export const canvasSlice = createSlice({ state.boundingBoxDimensions.width / ratio, 64 ); + state.scaledBoundingBoxDimensions.height = roundToMultiple( + state.scaledBoundingBoxDimensions.width / ratio, + 64 + ); } }); }, diff --git a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts index d8bb189abc..553d0770aa 100644 --- a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts +++ b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts @@ -73,7 +73,7 @@ export const parseSchema = ( const title = schema.title.replace('Invocation', ''); const tags = schema.tags ?? []; const description = schema.description ?? ''; - const version = schema.version ?? ''; + const version = schema.version; const inputs = reduce( schema.properties, diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamScaledHeight.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamScaledHeight.tsx index 7dae01bb91..6d0ac52b2f 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamScaledHeight.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamScaledHeight.tsx @@ -2,6 +2,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import IAISlider from 'common/components/IAISlider'; +import { roundToMultiple } from 'common/util/roundDownToMultiple'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { setScaledBoundingBoxDimensions } from 'features/canvas/store/canvasSlice'; import { generationSelector } from 'features/parameters/store/generationSelectors'; @@ -12,12 +13,13 @@ const selector = createSelector( [generationSelector, canvasSelector], (generation, canvas) => { const { scaledBoundingBoxDimensions, boundingBoxScaleMethod } = canvas; - const { model } = generation; + const { model, aspectRatio } = generation; return { model, scaledBoundingBoxDimensions, isManual: boundingBoxScaleMethod === 'manual', + aspectRatio, }; }, defaultSelectorOptions @@ -25,7 +27,7 @@ const selector = createSelector( const ParamScaledHeight = () => { const dispatch = useAppDispatch(); - const { model, isManual, scaledBoundingBoxDimensions } = + const { model, isManual, scaledBoundingBoxDimensions, aspectRatio } = useAppSelector(selector); const initial = ['sdxl', 'sdxl-refiner'].includes(model?.base_model as string) @@ -35,19 +37,33 @@ const ParamScaledHeight = () => { const { t } = useTranslation(); const handleChangeScaledHeight = (v: number) => { + let newWidth = scaledBoundingBoxDimensions.width; + const newHeight = Math.floor(v); + + if (aspectRatio) { + newWidth = roundToMultiple(newHeight * aspectRatio, 64); + } + dispatch( setScaledBoundingBoxDimensions({ - ...scaledBoundingBoxDimensions, - height: Math.floor(v), + width: newWidth, + height: newHeight, }) ); }; const handleResetScaledHeight = () => { + let resetWidth = scaledBoundingBoxDimensions.width; + const resetHeight = Math.floor(initial); + + if (aspectRatio) { + resetWidth = roundToMultiple(resetHeight * aspectRatio, 64); + } + dispatch( setScaledBoundingBoxDimensions({ - ...scaledBoundingBoxDimensions, - height: Math.floor(initial), + width: resetWidth, + height: resetHeight, }) ); }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamScaledWidth.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamScaledWidth.tsx index 0eda5a122c..71a8615d74 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamScaledWidth.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamScaledWidth.tsx @@ -2,6 +2,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import IAISlider from 'common/components/IAISlider'; +import { roundToMultiple } from 'common/util/roundDownToMultiple'; import { canvasSelector } from 'features/canvas/store/canvasSelectors'; import { setScaledBoundingBoxDimensions } from 'features/canvas/store/canvasSlice'; import { generationSelector } from 'features/parameters/store/generationSelectors'; @@ -12,11 +13,12 @@ const selector = createSelector( [canvasSelector, generationSelector], (canvas, generation) => { const { boundingBoxScaleMethod, scaledBoundingBoxDimensions } = canvas; - const { model } = generation; + const { model, aspectRatio } = generation; return { model, scaledBoundingBoxDimensions, + aspectRatio, isManual: boundingBoxScaleMethod === 'manual', }; }, @@ -25,7 +27,7 @@ const selector = createSelector( const ParamScaledWidth = () => { const dispatch = useAppDispatch(); - const { model, isManual, scaledBoundingBoxDimensions } = + const { model, isManual, scaledBoundingBoxDimensions, aspectRatio } = useAppSelector(selector); const initial = ['sdxl', 'sdxl-refiner'].includes(model?.base_model as string) @@ -35,19 +37,33 @@ const ParamScaledWidth = () => { const { t } = useTranslation(); const handleChangeScaledWidth = (v: number) => { + const newWidth = Math.floor(v); + let newHeight = scaledBoundingBoxDimensions.height; + + if (aspectRatio) { + newHeight = roundToMultiple(newWidth / aspectRatio, 64); + } + dispatch( setScaledBoundingBoxDimensions({ - ...scaledBoundingBoxDimensions, - width: Math.floor(v), + width: newWidth, + height: newHeight, }) ); }; const handleResetScaledWidth = () => { + const resetWidth = Math.floor(initial); + let resetHeight = scaledBoundingBoxDimensions.height; + + if (aspectRatio) { + resetHeight = roundToMultiple(resetWidth / aspectRatio, 64); + } + dispatch( setScaledBoundingBoxDimensions({ - ...scaledBoundingBoxDimensions, - width: Math.floor(initial), + width: resetWidth, + height: resetHeight, }) ); };