Merge branch 'main' into feat/nodes-phase-5

This commit is contained in:
blessedcoolant
2023-08-29 12:05:28 +12:00
78 changed files with 2008 additions and 786 deletions

View File

@@ -14,6 +14,7 @@ import i18n from 'i18n';
import { size } from 'lodash-es';
import { ReactNode, memo, useCallback, useEffect } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { usePreselectedImage } from '../../features/parameters/hooks/usePreselectedImage';
import AppErrorBoundaryFallback from './AppErrorBoundaryFallback';
import GlobalHotkeys from './GlobalHotkeys';
import Toaster from './Toaster';
@@ -23,13 +24,22 @@ const DEFAULT_CONFIG = {};
interface Props {
config?: PartialAppConfig;
headerComponent?: ReactNode;
selectedImage?: {
imageName: string;
action: 'sendToImg2Img' | 'sendToCanvas' | 'useAllParameters';
};
}
const App = ({ config = DEFAULT_CONFIG, headerComponent }: Props) => {
const App = ({
config = DEFAULT_CONFIG,
headerComponent,
selectedImage,
}: Props) => {
const language = useAppSelector(languageSelector);
const logger = useLogger('system');
const dispatch = useAppDispatch();
const { handlePreselectedImage } = usePreselectedImage();
const handleReset = useCallback(() => {
localStorage.clear();
location.reload();
@@ -51,6 +61,10 @@ const App = ({ config = DEFAULT_CONFIG, headerComponent }: Props) => {
dispatch(appStarted());
}, [dispatch]);
useEffect(() => {
handlePreselectedImage(selectedImage);
}, [handlePreselectedImage, selectedImage]);
return (
<ErrorBoundary
onReset={handleReset}

View File

@@ -26,6 +26,10 @@ interface Props extends PropsWithChildren {
headerComponent?: ReactNode;
middleware?: Middleware[];
projectId?: string;
selectedImage?: {
imageName: string;
action: 'sendToImg2Img' | 'sendToCanvas' | 'useAllParameters';
};
}
const InvokeAIUI = ({
@@ -35,6 +39,7 @@ const InvokeAIUI = ({
headerComponent,
middleware,
projectId,
selectedImage,
}: Props) => {
useEffect(() => {
// configure API client token
@@ -81,7 +86,11 @@ const InvokeAIUI = ({
<React.Suspense fallback={<Loading />}>
<ThemeLocaleProvider>
<AppDndContext>
<App config={config} headerComponent={headerComponent} />
<App
config={config}
headerComponent={headerComponent}
selectedImage={selectedImage}
/>
</AppDndContext>
</ThemeLocaleProvider>
</React.Suspense>

View File

@@ -1,4 +1,4 @@
import { Flex, MenuItem, Spinner } from '@chakra-ui/react';
import { Flex, MenuItem, Spinner, Text } from '@chakra-ui/react';
import { useAppToaster } from 'app/components/Toaster';
import { useAppDispatch } from 'app/store/storeHooks';
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
@@ -249,6 +249,18 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
>
{t('gallery.deleteImage')}
</MenuItem>
{metadata?.created_by && (
<Flex
sx={{
padding: '5px 10px',
marginTop: '5px',
}}
>
<Text fontSize="xs" fontWeight="bold">
Created by {metadata?.created_by}
</Text>
</Flex>
)}
</>
);
};

View File

@@ -8,7 +8,7 @@ import {
ImageDraggableData,
TypesafeDraggableData,
} from 'features/dnd/types';
import { useMultiselect } from 'features/gallery/hooks/useMultiselect.ts';
import { useMultiselect } from 'features/gallery/hooks/useMultiselect';
import { MouseEvent, memo, useCallback, useMemo, useState } from 'react';
import { FaTrash } from 'react-icons/fa';
import { MdStar, MdStarBorder } from 'react-icons/md';

View File

@@ -69,6 +69,9 @@ const ImageMetadataActions = (props: Props) => {
return (
<>
{metadata.created_by && (
<ImageMetadataItem label="Created By" value={metadata.created_by} />
)}
{metadata.generation_mode && (
<ImageMetadataItem
label="Generation Mode"

View File

@@ -10,6 +10,7 @@ import ColorInputField from './inputs/ColorInputField';
import ConditioningInputField from './inputs/ConditioningInputField';
import ControlInputField from './inputs/ControlInputField';
import ControlNetModelInputField from './inputs/ControlNetModelInputField';
import DenoiseMaskInputField from './inputs/DenoiseMaskInputField';
import EnumInputField from './inputs/EnumInputField';
import ImageCollectionInputField from './inputs/ImageCollectionInputField';
import ImageInputField from './inputs/ImageInputField';
@@ -105,6 +106,19 @@ const InputFieldRenderer = ({ nodeId, fieldName }: InputFieldProps) => {
);
}
if (
field?.type === 'DenoiseMaskField' &&
fieldTemplate?.type === 'DenoiseMaskField'
) {
return (
<DenoiseMaskInputField
nodeId={nodeId}
field={field}
fieldTemplate={fieldTemplate}
/>
);
}
if (
field?.type === 'ConditioningField' &&
fieldTemplate?.type === 'ConditioningField'

View File

@@ -0,0 +1,17 @@
import {
DenoiseMaskInputFieldTemplate,
DenoiseMaskInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types';
import { memo } from 'react';
const DenoiseMaskInputFieldComponent = (
_props: FieldComponentProps<
DenoiseMaskInputFieldValue,
DenoiseMaskInputFieldTemplate
>
) => {
return null;
};
export default memo(DenoiseMaskInputFieldComponent);

View File

@@ -59,6 +59,11 @@ export const FIELDS: Record<FieldType, FieldUIConfig> = {
description: 'Images may be passed between nodes.',
color: 'purple.500',
},
DenoiseMaskField: {
title: 'Denoise Mask',
description: 'Denoise Mask may be passed between nodes',
color: 'red.700',
},
LatentsField: {
title: 'Latents',
description: 'Latents may be passed between nodes.',

View File

@@ -65,6 +65,7 @@ export const zFieldType = z.enum([
'string',
'array',
'ImageField',
'DenoiseMaskField',
'LatentsField',
'ConditioningField',
'ControlField',
@@ -129,6 +130,7 @@ export type InputFieldTemplate =
| StringInputFieldTemplate
| BooleanInputFieldTemplate
| ImageInputFieldTemplate
| DenoiseMaskInputFieldTemplate
| LatentsInputFieldTemplate
| ConditioningInputFieldTemplate
| UNetInputFieldTemplate
@@ -214,6 +216,12 @@ export const zConditioningField = z.object({
});
export type ConditioningField = z.infer<typeof zConditioningField>;
export const zDenoiseMaskField = z.object({
mask_name: z.string().trim().min(1),
masked_latents_name: z.string().trim().min(1).optional(),
});
export type DenoiseMaskFieldValue = z.infer<typeof zDenoiseMaskField>;
export const zIntegerInputFieldValue = zInputFieldValueBase.extend({
type: z.literal('integer'),
value: z.number().optional(),
@@ -250,6 +258,14 @@ export const zLatentsInputFieldValue = zInputFieldValueBase.extend({
});
export type LatentsInputFieldValue = z.infer<typeof zLatentsInputFieldValue>;
export const zDenoiseMaskInputFieldValue = zInputFieldValueBase.extend({
type: z.literal('DenoiseMaskField'),
value: zDenoiseMaskField.optional(),
});
export type DenoiseMaskInputFieldValue = z.infer<
typeof zDenoiseMaskInputFieldValue
>;
export const zConditioningInputFieldValue = zInputFieldValueBase.extend({
type: z.literal('ConditioningField'),
value: zConditioningField.optional(),
@@ -468,6 +484,7 @@ export const zInputFieldValue = z.discriminatedUnion('type', [
zBooleanInputFieldValue,
zImageInputFieldValue,
zLatentsInputFieldValue,
zDenoiseMaskInputFieldValue,
zConditioningInputFieldValue,
zUNetInputFieldValue,
zClipInputFieldValue,
@@ -541,6 +558,11 @@ export type ImageCollectionInputFieldTemplate = InputFieldTemplateBase & {
type: 'ImageCollection';
};
export type DenoiseMaskInputFieldTemplate = InputFieldTemplateBase & {
default: undefined;
type: 'DenoiseMaskField';
};
export type LatentsInputFieldTemplate = InputFieldTemplateBase & {
default: string;
type: 'LatentsField';

View File

@@ -8,6 +8,7 @@ import {
ConditioningInputFieldTemplate,
ControlInputFieldTemplate,
ControlNetModelInputFieldTemplate,
DenoiseMaskInputFieldTemplate,
EnumInputFieldTemplate,
FieldType,
FloatInputFieldTemplate,
@@ -262,6 +263,19 @@ const buildImageCollectionInputFieldTemplate = ({
return template;
};
const buildDenoiseMaskInputFieldTemplate = ({
schemaObject,
baseField,
}: BuildInputFieldArg): DenoiseMaskInputFieldTemplate => {
const template: DenoiseMaskInputFieldTemplate = {
...baseField,
type: 'DenoiseMaskField',
default: schemaObject.default ?? undefined,
};
return template;
};
const buildLatentsInputFieldTemplate = ({
schemaObject,
baseField,
@@ -488,6 +502,12 @@ export const buildInputFieldTemplate = (
baseField,
});
}
if (fieldType === 'DenoiseMaskField') {
return buildDenoiseMaskInputFieldTemplate({
schemaObject: fieldSchema,
baseField,
});
}
if (fieldType === 'LatentsField') {
return buildLatentsInputFieldTemplate({
schemaObject: fieldSchema,

View File

@@ -49,6 +49,10 @@ export const buildInputFieldValue = (
fieldValue.value = [];
}
if (template.type === 'DenoiseMaskField') {
fieldValue.value = undefined;
}
if (template.type === 'LatentsField') {
fieldValue.value = undefined;
}

View File

@@ -63,7 +63,7 @@ export const addDynamicPromptsToGraph = (
{
source: {
node_id: DYNAMIC_PROMPT,
field: 'prompt_collection',
field: 'collection',
},
destination: {
node_id: ITERATE,

View File

@@ -11,9 +11,11 @@ import {
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
POSITIVE_CONDITIONING,
REFINER_SEAMLESS,
SDXL_CANVAS_INPAINT_GRAPH,
SDXL_CANVAS_OUTPAINT_GRAPH,
SDXL_MODEL_LOADER,
SEAMLESS,
} from './constants';
export const addSDXLLoRAsToGraph = (
@@ -36,20 +38,25 @@ export const addSDXLLoRAsToGraph = (
| MetadataAccumulatorInvocation
| undefined;
// Handle Seamless Plugs
const unetLoaderId = modelLoaderNodeId;
let clipLoaderId = modelLoaderNodeId;
if ([SEAMLESS, REFINER_SEAMLESS].includes(modelLoaderNodeId)) {
clipLoaderId = SDXL_MODEL_LOADER;
}
if (loraCount > 0) {
// Remove modelLoaderNodeId unet/clip/clip2 connections to feed it to LoRAs
graph.edges = graph.edges.filter(
(e) =>
!(
e.source.node_id === modelLoaderNodeId &&
['unet'].includes(e.source.field)
e.source.node_id === unetLoaderId && ['unet'].includes(e.source.field)
) &&
!(
e.source.node_id === modelLoaderNodeId &&
['clip'].includes(e.source.field)
e.source.node_id === clipLoaderId && ['clip'].includes(e.source.field)
) &&
!(
e.source.node_id === modelLoaderNodeId &&
e.source.node_id === clipLoaderId &&
['clip2'].includes(e.source.field)
)
);
@@ -88,7 +95,7 @@ export const addSDXLLoRAsToGraph = (
// first lora = start the lora chain, attach directly to model loader
graph.edges.push({
source: {
node_id: modelLoaderNodeId,
node_id: unetLoaderId,
field: 'unet',
},
destination: {
@@ -99,7 +106,7 @@ export const addSDXLLoRAsToGraph = (
graph.edges.push({
source: {
node_id: modelLoaderNodeId,
node_id: clipLoaderId,
field: 'clip',
},
destination: {
@@ -110,7 +117,7 @@ export const addSDXLLoRAsToGraph = (
graph.edges.push({
source: {
node_id: modelLoaderNodeId,
node_id: clipLoaderId,
field: 'clip2',
},
destination: {

View File

@@ -1,11 +1,15 @@
import { RootState } from 'app/store/store';
import { MetadataAccumulatorInvocation } from 'services/api/types';
import {
MetadataAccumulatorInvocation,
SeamlessModeInvocation,
} from 'services/api/types';
import { NonNullableGraph } from '../../types/types';
import {
CANVAS_OUTPUT,
LATENTS_TO_IMAGE,
MASK_BLUR,
METADATA_ACCUMULATOR,
REFINER_SEAMLESS,
SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH,
SDXL_CANVAS_INPAINT_GRAPH,
SDXL_CANVAS_OUTPAINT_GRAPH,
@@ -21,7 +25,8 @@ import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt';
export const addSDXLRefinerToGraph = (
state: RootState,
graph: NonNullableGraph,
baseNodeId: string
baseNodeId: string,
modelLoaderNodeId?: string
): void => {
const {
refinerModel,
@@ -33,6 +38,8 @@ export const addSDXLRefinerToGraph = (
refinerStart,
} = state.sdxl;
const { seamlessXAxis, seamlessYAxis } = state.generation;
if (!refinerModel) {
return;
}
@@ -53,6 +60,10 @@ export const addSDXLRefinerToGraph = (
metadataAccumulator.refiner_steps = refinerSteps;
}
const modelLoaderId = modelLoaderNodeId
? modelLoaderNodeId
: SDXL_MODEL_LOADER;
// Construct Style Prompt
const { craftedPositiveStylePrompt, craftedNegativeStylePrompt } =
craftSDXLStylePrompt(state, true);
@@ -65,10 +76,7 @@ export const addSDXLRefinerToGraph = (
graph.edges = graph.edges.filter(
(e) =>
!(
e.source.node_id === SDXL_MODEL_LOADER &&
['vae'].includes(e.source.field)
)
!(e.source.node_id === modelLoaderId && ['vae'].includes(e.source.field))
);
graph.nodes[SDXL_REFINER_MODEL_LOADER] = {
@@ -98,8 +106,39 @@ export const addSDXLRefinerToGraph = (
denoising_end: 1,
};
graph.edges.push(
{
// Add Seamless To Refiner
if (seamlessXAxis || seamlessYAxis) {
graph.nodes[REFINER_SEAMLESS] = {
id: REFINER_SEAMLESS,
type: 'seamless',
seamless_x: seamlessXAxis,
seamless_y: seamlessYAxis,
} as SeamlessModeInvocation;
graph.edges.push(
{
source: {
node_id: SDXL_REFINER_MODEL_LOADER,
field: 'unet',
},
destination: {
node_id: REFINER_SEAMLESS,
field: 'unet',
},
},
{
source: {
node_id: REFINER_SEAMLESS,
field: 'unet',
},
destination: {
node_id: SDXL_REFINER_DENOISE_LATENTS,
field: 'unet',
},
}
);
} else {
graph.edges.push({
source: {
node_id: SDXL_REFINER_MODEL_LOADER,
field: 'unet',
@@ -108,7 +147,10 @@ export const addSDXLRefinerToGraph = (
node_id: SDXL_REFINER_DENOISE_LATENTS,
field: 'unet',
},
},
});
}
graph.edges.push(
{
source: {
node_id: SDXL_REFINER_MODEL_LOADER,

View File

@@ -0,0 +1,109 @@
import { RootState } from 'app/store/store';
import { SeamlessModeInvocation } from 'services/api/types';
import { NonNullableGraph } from '../../types/types';
import {
CANVAS_COHERENCE_DENOISE_LATENTS,
CANVAS_INPAINT_GRAPH,
CANVAS_OUTPAINT_GRAPH,
DENOISE_LATENTS,
SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH,
SDXL_CANVAS_INPAINT_GRAPH,
SDXL_CANVAS_OUTPAINT_GRAPH,
SDXL_CANVAS_TEXT_TO_IMAGE_GRAPH,
SDXL_DENOISE_LATENTS,
SDXL_IMAGE_TO_IMAGE_GRAPH,
SDXL_TEXT_TO_IMAGE_GRAPH,
SEAMLESS,
} from './constants';
export const addSeamlessToLinearGraph = (
state: RootState,
graph: NonNullableGraph,
modelLoaderNodeId: string
): void => {
// Remove Existing UNet Connections
const { seamlessXAxis, seamlessYAxis } = state.generation;
graph.nodes[SEAMLESS] = {
id: SEAMLESS,
type: 'seamless',
seamless_x: seamlessXAxis,
seamless_y: seamlessYAxis,
} as SeamlessModeInvocation;
let denoisingNodeId = DENOISE_LATENTS;
if (
graph.id === SDXL_TEXT_TO_IMAGE_GRAPH ||
graph.id === SDXL_IMAGE_TO_IMAGE_GRAPH ||
graph.id === SDXL_CANVAS_TEXT_TO_IMAGE_GRAPH ||
graph.id === SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH ||
graph.id === SDXL_CANVAS_INPAINT_GRAPH ||
graph.id === SDXL_CANVAS_OUTPAINT_GRAPH
) {
denoisingNodeId = SDXL_DENOISE_LATENTS;
}
graph.edges = graph.edges.filter(
(e) =>
!(
e.source.node_id === modelLoaderNodeId &&
['unet'].includes(e.source.field)
) &&
!(
e.source.node_id === modelLoaderNodeId &&
['vae'].includes(e.source.field)
)
);
graph.edges.push(
{
source: {
node_id: modelLoaderNodeId,
field: 'unet',
},
destination: {
node_id: SEAMLESS,
field: 'unet',
},
},
{
source: {
node_id: modelLoaderNodeId,
field: 'vae',
},
destination: {
node_id: SEAMLESS,
field: 'vae',
},
},
{
source: {
node_id: SEAMLESS,
field: 'unet',
},
destination: {
node_id: denoisingNodeId,
field: 'unet',
},
}
);
if (
graph.id == CANVAS_INPAINT_GRAPH ||
graph.id === CANVAS_OUTPAINT_GRAPH ||
graph.id === SDXL_CANVAS_INPAINT_GRAPH ||
graph.id === SDXL_CANVAS_OUTPAINT_GRAPH
) {
graph.edges.push({
source: {
node_id: SEAMLESS,
field: 'unet',
},
destination: {
node_id: CANVAS_COHERENCE_DENOISE_LATENTS,
field: 'unet',
},
});
}
};

View File

@@ -9,6 +9,7 @@ import {
CANVAS_TEXT_TO_IMAGE_GRAPH,
IMAGE_TO_IMAGE_GRAPH,
IMAGE_TO_LATENTS,
INPAINT_CREATE_MASK,
INPAINT_IMAGE,
LATENTS_TO_IMAGE,
MAIN_MODEL_LOADER,
@@ -30,6 +31,11 @@ export const addVAEToGraph = (
modelLoaderNodeId: string = MAIN_MODEL_LOADER
): void => {
const { vae } = state.generation;
const { boundingBoxScaleMethod } = state.canvas;
const isUsingScaledDimensions = ['auto', 'manual'].includes(
boundingBoxScaleMethod
);
const isAutoVae = !vae;
const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as
@@ -76,7 +82,7 @@ export const addVAEToGraph = (
field: isAutoVae && isOnnxModel ? 'vae_decoder' : 'vae',
},
destination: {
node_id: CANVAS_OUTPUT,
node_id: isUsingScaledDimensions ? LATENTS_TO_IMAGE : CANVAS_OUTPUT,
field: 'vae',
},
});
@@ -117,6 +123,16 @@ export const addVAEToGraph = (
field: 'vae',
},
},
{
source: {
node_id: isAutoVae ? modelLoaderNodeId : VAE_LOADER,
field: isAutoVae && isOnnxModel ? 'vae_decoder' : 'vae',
},
destination: {
node_id: INPAINT_CREATE_MASK,
field: 'vae',
},
},
{
source: {
node_id: isAutoVae ? modelLoaderNodeId : VAE_LOADER,

View File

@@ -2,15 +2,12 @@ import { logger } from 'app/logging/logger';
import { RootState } from 'app/store/store';
import { NonNullableGraph } from 'features/nodes/types/types';
import { initialGenerationState } from 'features/parameters/store/generationSlice';
import {
ImageDTO,
ImageResizeInvocation,
ImageToLatentsInvocation,
} from 'services/api/types';
import { ImageDTO, ImageToLatentsInvocation } from 'services/api/types';
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
import { addLoRAsToGraph } from './addLoRAsToGraph';
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
@@ -19,12 +16,14 @@ import {
CLIP_SKIP,
DENOISE_LATENTS,
IMAGE_TO_LATENTS,
IMG2IMG_RESIZE,
LATENTS_TO_IMAGE,
MAIN_MODEL_LOADER,
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
NOISE,
POSITIVE_CONDITIONING,
RESIZE,
SEAMLESS,
} from './constants';
/**
@@ -43,21 +42,34 @@ export const buildCanvasImageToImageGraph = (
scheduler,
steps,
img2imgStrength: strength,
vaePrecision,
clipSkip,
shouldUseCpuNoise,
shouldUseNoiseSettings,
seamlessXAxis,
seamlessYAxis,
} = state.generation;
// The bounding box determines width and height, not the width and height params
const { width, height } = state.canvas.boundingBoxDimensions;
const { shouldAutoSave } = state.canvas;
const {
scaledBoundingBoxDimensions,
boundingBoxScaleMethod,
shouldAutoSave,
} = state.canvas;
const isUsingScaledDimensions = ['auto', 'manual'].includes(
boundingBoxScaleMethod
);
if (!model) {
log.error('No model found in state');
throw new Error('No model found in state');
}
let modelLoaderNodeId = MAIN_MODEL_LOADER;
const use_cpu = shouldUseNoiseSettings
? shouldUseCpuNoise
: initialGenerationState.shouldUseCpuNoise;
@@ -75,9 +87,9 @@ export const buildCanvasImageToImageGraph = (
const graph: NonNullableGraph = {
id: CANVAS_IMAGE_TO_IMAGE_GRAPH,
nodes: {
[MAIN_MODEL_LOADER]: {
[modelLoaderNodeId]: {
type: 'main_model_loader',
id: MAIN_MODEL_LOADER,
id: modelLoaderNodeId,
is_intermediate: true,
model,
},
@@ -104,15 +116,17 @@ export const buildCanvasImageToImageGraph = (
id: NOISE,
is_intermediate: true,
use_cpu,
width: !isUsingScaledDimensions
? width
: scaledBoundingBoxDimensions.width,
height: !isUsingScaledDimensions
? height
: scaledBoundingBoxDimensions.height,
},
[IMAGE_TO_LATENTS]: {
type: 'i2l',
id: IMAGE_TO_LATENTS,
is_intermediate: true,
// must be set manually later, bc `fit` parameter may require a resize node inserted
// image: {
// image_name: initialImage.image_name,
// },
},
[DENOISE_LATENTS]: {
type: 'denoise_latents',
@@ -134,7 +148,7 @@ export const buildCanvasImageToImageGraph = (
// Connect Model Loader to CLIP Skip and UNet
{
source: {
node_id: MAIN_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'unet',
},
destination: {
@@ -144,7 +158,7 @@ export const buildCanvasImageToImageGraph = (
},
{
source: {
node_id: MAIN_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip',
},
destination: {
@@ -214,82 +228,84 @@ export const buildCanvasImageToImageGraph = (
field: 'latents',
},
},
// Decode the denoised latents to an image
],
};
// Decode Latents To Image & Handle Scaled Before Processing
if (isUsingScaledDimensions) {
graph.nodes[IMG2IMG_RESIZE] = {
id: IMG2IMG_RESIZE,
type: 'img_resize',
is_intermediate: true,
image: initialImage,
width: scaledBoundingBoxDimensions.width,
height: scaledBoundingBoxDimensions.height,
};
graph.nodes[LATENTS_TO_IMAGE] = {
id: LATENTS_TO_IMAGE,
type: 'l2i',
is_intermediate: true,
fp32: vaePrecision === 'fp32' ? true : false,
};
graph.nodes[CANVAS_OUTPUT] = {
id: CANVAS_OUTPUT,
type: 'img_resize',
is_intermediate: !shouldAutoSave,
width: width,
height: height,
};
graph.edges.push(
{
source: {
node_id: IMG2IMG_RESIZE,
field: 'image',
},
destination: {
node_id: IMAGE_TO_LATENTS,
field: 'image',
},
},
{
source: {
node_id: DENOISE_LATENTS,
field: 'latents',
},
destination: {
node_id: CANVAS_OUTPUT,
node_id: LATENTS_TO_IMAGE,
field: 'latents',
},
},
],
};
// handle `fit`
if (initialImage.width !== width || initialImage.height !== height) {
// The init image needs to be resized to the specified width and height before being passed to `IMAGE_TO_LATENTS`
// Create a resize node, explicitly setting its image
const resizeNode: ImageResizeInvocation = {
id: RESIZE,
type: 'img_resize',
image: {
image_name: initialImage.image_name,
},
is_intermediate: true,
width,
height,
};
graph.nodes[RESIZE] = resizeNode;
// The `RESIZE` node then passes its image to `IMAGE_TO_LATENTS`
graph.edges.push({
source: { node_id: RESIZE, field: 'image' },
destination: {
node_id: IMAGE_TO_LATENTS,
field: 'image',
},
});
// The `RESIZE` node also passes its width and height to `NOISE`
graph.edges.push({
source: { node_id: RESIZE, field: 'width' },
destination: {
node_id: NOISE,
field: 'width',
},
});
graph.edges.push({
source: { node_id: RESIZE, field: 'height' },
destination: {
node_id: NOISE,
field: 'height',
},
});
{
source: {
node_id: LATENTS_TO_IMAGE,
field: 'image',
},
destination: {
node_id: CANVAS_OUTPUT,
field: 'image',
},
}
);
} else {
// We are not resizing, so we need to set the image on the `IMAGE_TO_LATENTS` node explicitly
(graph.nodes[IMAGE_TO_LATENTS] as ImageToLatentsInvocation).image = {
image_name: initialImage.image_name,
graph.nodes[CANVAS_OUTPUT] = {
type: 'l2i',
id: CANVAS_OUTPUT,
is_intermediate: !shouldAutoSave,
fp32: vaePrecision === 'fp32' ? true : false,
};
// Pass the image's dimensions to the `NOISE` node
(graph.nodes[IMAGE_TO_LATENTS] as ImageToLatentsInvocation).image =
initialImage;
graph.edges.push({
source: { node_id: IMAGE_TO_LATENTS, field: 'width' },
destination: {
node_id: NOISE,
field: 'width',
source: {
node_id: DENOISE_LATENTS,
field: 'latents',
},
});
graph.edges.push({
source: { node_id: IMAGE_TO_LATENTS, field: 'height' },
destination: {
node_id: NOISE,
field: 'height',
node_id: CANVAS_OUTPUT,
field: 'latents',
},
});
}
@@ -300,8 +316,10 @@ export const buildCanvasImageToImageGraph = (
type: 'metadata_accumulator',
generation_mode: 'img2img',
cfg_scale,
height,
width,
width: !isUsingScaledDimensions ? width : scaledBoundingBoxDimensions.width,
height: !isUsingScaledDimensions
? height
: scaledBoundingBoxDimensions.height,
positive_prompt: '', // set in addDynamicPromptsToGraph
negative_prompt: negativePrompt,
model,
@@ -328,11 +346,17 @@ export const buildCanvasImageToImageGraph = (
},
});
// Add Seamless To Graph
if (seamlessXAxis || seamlessYAxis) {
addSeamlessToLinearGraph(state, graph, modelLoaderNodeId);
modelLoaderNodeId = SEAMLESS;
}
// add LoRA support
addLoRAsToGraph(state, graph, DENOISE_LATENTS);
// optionally add custom VAE
addVAEToGraph(state, graph, MAIN_MODEL_LOADER);
addVAEToGraph(state, graph, modelLoaderNodeId);
// add dynamic prompts - also sets up core iteration and seed
addDynamicPromptsToGraph(state, graph);

View File

@@ -2,6 +2,7 @@ import { logger } from 'app/logging/logger';
import { RootState } from 'app/store/store';
import { NonNullableGraph } from 'features/nodes/types/types';
import {
CreateDenoiseMaskInvocation,
ImageBlurInvocation,
ImageDTO,
ImageToLatentsInvocation,
@@ -12,16 +13,18 @@ import {
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
import { addLoRAsToGraph } from './addLoRAsToGraph';
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
CANVAS_INPAINT_GRAPH,
CANVAS_OUTPUT,
CANVAS_COHERENCE_DENOISE_LATENTS,
CANVAS_COHERENCE_NOISE,
CANVAS_COHERENCE_NOISE_INCREMENT,
CANVAS_INPAINT_GRAPH,
CANVAS_OUTPUT,
CLIP_SKIP,
DENOISE_LATENTS,
INPAINT_CREATE_MASK,
INPAINT_IMAGE,
INPAINT_IMAGE_RESIZE_DOWN,
INPAINT_IMAGE_RESIZE_UP,
@@ -36,6 +39,7 @@ import {
POSITIVE_CONDITIONING,
RANDOM_INT,
RANGE_OF_SIZE,
SEAMLESS,
} from './constants';
/**
@@ -66,6 +70,8 @@ export const buildCanvasInpaintGraph = (
canvasCoherenceSteps,
canvasCoherenceStrength,
clipSkip,
seamlessXAxis,
seamlessYAxis,
} = state.generation;
if (!model) {
@@ -83,6 +89,8 @@ export const buildCanvasInpaintGraph = (
shouldAutoSave,
} = state.canvas;
let modelLoaderNodeId = MAIN_MODEL_LOADER;
const use_cpu = shouldUseNoiseSettings
? shouldUseCpuNoise
: shouldUseCpuNoise;
@@ -90,9 +98,9 @@ export const buildCanvasInpaintGraph = (
const graph: NonNullableGraph = {
id: CANVAS_INPAINT_GRAPH,
nodes: {
[MAIN_MODEL_LOADER]: {
[modelLoaderNodeId]: {
type: 'main_model_loader',
id: MAIN_MODEL_LOADER,
id: modelLoaderNodeId,
is_intermediate: true,
model,
},
@@ -127,6 +135,12 @@ export const buildCanvasInpaintGraph = (
is_intermediate: true,
fp32: vaePrecision === 'fp32' ? true : false,
},
[INPAINT_CREATE_MASK]: {
type: 'create_denoise_mask',
id: INPAINT_CREATE_MASK,
is_intermediate: true,
fp32: vaePrecision === 'fp32' ? true : false,
},
[NOISE]: {
type: 'noise',
id: NOISE,
@@ -196,7 +210,7 @@ export const buildCanvasInpaintGraph = (
// Connect Model Loader to CLIP Skip and UNet
{
source: {
node_id: MAIN_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'unet',
},
destination: {
@@ -206,7 +220,7 @@ export const buildCanvasInpaintGraph = (
},
{
source: {
node_id: MAIN_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip',
},
destination: {
@@ -276,16 +290,27 @@ export const buildCanvasInpaintGraph = (
field: 'latents',
},
},
// Create Inpaint Mask
{
source: {
node_id: MASK_BLUR,
field: 'image',
},
destination: {
node_id: DENOISE_LATENTS,
node_id: INPAINT_CREATE_MASK,
field: 'mask',
},
},
{
source: {
node_id: INPAINT_CREATE_MASK,
field: 'denoise_mask',
},
destination: {
node_id: DENOISE_LATENTS,
field: 'denoise_mask',
},
},
// Iterate
{
source: {
@@ -330,7 +355,7 @@ export const buildCanvasInpaintGraph = (
},
{
source: {
node_id: MAIN_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'unet',
},
destination: {
@@ -459,6 +484,16 @@ export const buildCanvasInpaintGraph = (
field: 'image',
},
},
{
source: {
node_id: INPAINT_IMAGE_RESIZE_UP,
field: 'image',
},
destination: {
node_id: INPAINT_CREATE_MASK,
field: 'image',
},
},
// Color Correct The Inpainted Result
{
source: {
@@ -516,6 +551,10 @@ export const buildCanvasInpaintGraph = (
...(graph.nodes[MASK_BLUR] as ImageBlurInvocation),
image: canvasMaskImage,
};
graph.nodes[INPAINT_CREATE_MASK] = {
...(graph.nodes[INPAINT_CREATE_MASK] as CreateDenoiseMaskInvocation),
image: canvasInitImage,
};
graph.edges.push(
// Color Correct The Inpainted Result
@@ -562,11 +601,17 @@ export const buildCanvasInpaintGraph = (
(graph.nodes[RANGE_OF_SIZE] as RangeOfSizeInvocation).start = seed;
}
// Add Seamless To Graph
if (seamlessXAxis || seamlessYAxis) {
addSeamlessToLinearGraph(state, graph, modelLoaderNodeId);
modelLoaderNodeId = SEAMLESS;
}
// Add VAE
addVAEToGraph(state, graph, MAIN_MODEL_LOADER);
addVAEToGraph(state, graph, modelLoaderNodeId);
// add LoRA support
addLoRAsToGraph(state, graph, DENOISE_LATENTS, MAIN_MODEL_LOADER);
addLoRAsToGraph(state, graph, DENOISE_LATENTS, modelLoaderNodeId);
// add controlnet, mutating `graph`
addControlNetToLinearGraph(state, graph, DENOISE_LATENTS);

View File

@@ -14,16 +14,18 @@ import {
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
import { addLoRAsToGraph } from './addLoRAsToGraph';
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
CANVAS_OUTPAINT_GRAPH,
CANVAS_OUTPUT,
CANVAS_COHERENCE_DENOISE_LATENTS,
CANVAS_COHERENCE_NOISE,
CANVAS_COHERENCE_NOISE_INCREMENT,
CANVAS_OUTPAINT_GRAPH,
CANVAS_OUTPUT,
CLIP_SKIP,
DENOISE_LATENTS,
INPAINT_CREATE_MASK,
INPAINT_IMAGE,
INPAINT_IMAGE_RESIZE_DOWN,
INPAINT_IMAGE_RESIZE_UP,
@@ -42,6 +44,7 @@ import {
POSITIVE_CONDITIONING,
RANDOM_INT,
RANGE_OF_SIZE,
SEAMLESS,
} from './constants';
/**
@@ -74,6 +77,8 @@ export const buildCanvasOutpaintGraph = (
tileSize,
infillMethod,
clipSkip,
seamlessXAxis,
seamlessYAxis,
} = state.generation;
if (!model) {
@@ -91,6 +96,8 @@ export const buildCanvasOutpaintGraph = (
shouldAutoSave,
} = state.canvas;
let modelLoaderNodeId = MAIN_MODEL_LOADER;
const use_cpu = shouldUseNoiseSettings
? shouldUseCpuNoise
: shouldUseCpuNoise;
@@ -98,9 +105,9 @@ export const buildCanvasOutpaintGraph = (
const graph: NonNullableGraph = {
id: CANVAS_OUTPAINT_GRAPH,
nodes: {
[MAIN_MODEL_LOADER]: {
[modelLoaderNodeId]: {
type: 'main_model_loader',
id: MAIN_MODEL_LOADER,
id: modelLoaderNodeId,
is_intermediate: true,
model,
},
@@ -153,6 +160,12 @@ export const buildCanvasOutpaintGraph = (
use_cpu,
is_intermediate: true,
},
[INPAINT_CREATE_MASK]: {
type: 'create_denoise_mask',
id: INPAINT_CREATE_MASK,
is_intermediate: true,
fp32: vaePrecision === 'fp32' ? true : false,
},
[DENOISE_LATENTS]: {
type: 'denoise_latents',
id: DENOISE_LATENTS,
@@ -215,7 +228,7 @@ export const buildCanvasOutpaintGraph = (
// Connect Model Loader To UNet & Clip Skip
{
source: {
node_id: MAIN_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'unet',
},
destination: {
@@ -225,7 +238,7 @@ export const buildCanvasOutpaintGraph = (
},
{
source: {
node_id: MAIN_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip',
},
destination: {
@@ -317,16 +330,27 @@ export const buildCanvasOutpaintGraph = (
field: 'latents',
},
},
// Create Inpaint Mask
{
source: {
node_id: MASK_BLUR,
field: 'image',
},
destination: {
node_id: DENOISE_LATENTS,
node_id: INPAINT_CREATE_MASK,
field: 'mask',
},
},
{
source: {
node_id: INPAINT_CREATE_MASK,
field: 'denoise_mask',
},
destination: {
node_id: DENOISE_LATENTS,
field: 'denoise_mask',
},
},
// Iterate
{
source: {
@@ -371,7 +395,7 @@ export const buildCanvasOutpaintGraph = (
},
{
source: {
node_id: MAIN_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'unet',
},
destination: {
@@ -522,6 +546,16 @@ export const buildCanvasOutpaintGraph = (
field: 'image',
},
},
{
source: {
node_id: INPAINT_INFILL,
field: 'image',
},
destination: {
node_id: INPAINT_CREATE_MASK,
field: 'image',
},
},
// Take combined mask and resize and then blur
{
source: {
@@ -640,6 +674,16 @@ export const buildCanvasOutpaintGraph = (
field: 'image',
},
},
{
source: {
node_id: INPAINT_INFILL,
field: 'image',
},
destination: {
node_id: INPAINT_CREATE_MASK,
field: 'image',
},
},
// Color Correct The Inpainted Result
{
source: {
@@ -694,11 +738,17 @@ export const buildCanvasOutpaintGraph = (
(graph.nodes[RANGE_OF_SIZE] as RangeOfSizeInvocation).start = seed;
}
// Add Seamless To Graph
if (seamlessXAxis || seamlessYAxis) {
addSeamlessToLinearGraph(state, graph, modelLoaderNodeId);
modelLoaderNodeId = SEAMLESS;
}
// Add VAE
addVAEToGraph(state, graph, MAIN_MODEL_LOADER);
addVAEToGraph(state, graph, modelLoaderNodeId);
// add LoRA support
addLoRAsToGraph(state, graph, DENOISE_LATENTS, MAIN_MODEL_LOADER);
addLoRAsToGraph(state, graph, DENOISE_LATENTS, modelLoaderNodeId);
// add controlnet, mutating `graph`
addControlNetToLinearGraph(state, graph, DENOISE_LATENTS);

View File

@@ -2,29 +2,29 @@ import { logger } from 'app/logging/logger';
import { RootState } from 'app/store/store';
import { NonNullableGraph } from 'features/nodes/types/types';
import { initialGenerationState } from 'features/parameters/store/generationSlice';
import {
ImageDTO,
ImageResizeInvocation,
ImageToLatentsInvocation,
} from 'services/api/types';
import { ImageDTO, ImageToLatentsInvocation } from 'services/api/types';
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
CANVAS_OUTPUT,
IMAGE_TO_LATENTS,
IMG2IMG_RESIZE,
LATENTS_TO_IMAGE,
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
NOISE,
POSITIVE_CONDITIONING,
RESIZE,
REFINER_SEAMLESS,
SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH,
SDXL_DENOISE_LATENTS,
SDXL_MODEL_LOADER,
SEAMLESS,
} from './constants';
import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt';
@@ -47,6 +47,8 @@ export const buildCanvasSDXLImageToImageGraph = (
clipSkip,
shouldUseCpuNoise,
shouldUseNoiseSettings,
seamlessXAxis,
seamlessYAxis,
} = state.generation;
const {
@@ -59,13 +61,24 @@ export const buildCanvasSDXLImageToImageGraph = (
// The bounding box determines width and height, not the width and height params
const { width, height } = state.canvas.boundingBoxDimensions;
const { shouldAutoSave } = state.canvas;
const {
scaledBoundingBoxDimensions,
boundingBoxScaleMethod,
shouldAutoSave,
} = state.canvas;
const isUsingScaledDimensions = ['auto', 'manual'].includes(
boundingBoxScaleMethod
);
if (!model) {
log.error('No model found in state');
throw new Error('No model found in state');
}
// Model Loader ID
let modelLoaderNodeId = SDXL_MODEL_LOADER;
const use_cpu = shouldUseNoiseSettings
? shouldUseCpuNoise
: initialGenerationState.shouldUseCpuNoise;
@@ -87,9 +100,9 @@ export const buildCanvasSDXLImageToImageGraph = (
const graph: NonNullableGraph = {
id: SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH,
nodes: {
[SDXL_MODEL_LOADER]: {
[modelLoaderNodeId]: {
type: 'sdxl_model_loader',
id: SDXL_MODEL_LOADER,
id: modelLoaderNodeId,
model,
},
[POSITIVE_CONDITIONING]: {
@@ -109,16 +122,18 @@ export const buildCanvasSDXLImageToImageGraph = (
id: NOISE,
is_intermediate: true,
use_cpu,
width: !isUsingScaledDimensions
? width
: scaledBoundingBoxDimensions.width,
height: !isUsingScaledDimensions
? height
: scaledBoundingBoxDimensions.height,
},
[IMAGE_TO_LATENTS]: {
type: 'i2l',
id: IMAGE_TO_LATENTS,
is_intermediate: true,
fp32: vaePrecision === 'fp32' ? true : false,
// must be set manually later, bc `fit` parameter may require a resize node inserted
// image: {
// image_name: initialImage.image_name,
// },
},
[SDXL_DENOISE_LATENTS]: {
type: 'denoise_latents',
@@ -132,18 +147,12 @@ export const buildCanvasSDXLImageToImageGraph = (
: 1 - strength,
denoising_end: shouldUseSDXLRefiner ? refinerStart : 1,
},
[CANVAS_OUTPUT]: {
type: 'l2i',
id: CANVAS_OUTPUT,
is_intermediate: !shouldAutoSave,
fp32: vaePrecision === 'fp32' ? true : false,
},
},
edges: [
// Connect Model Loader To UNet & CLIP
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'unet',
},
destination: {
@@ -153,7 +162,7 @@ export const buildCanvasSDXLImageToImageGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip',
},
destination: {
@@ -163,7 +172,7 @@ export const buildCanvasSDXLImageToImageGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip2',
},
destination: {
@@ -173,7 +182,7 @@ export const buildCanvasSDXLImageToImageGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip',
},
destination: {
@@ -183,7 +192,7 @@ export const buildCanvasSDXLImageToImageGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip2',
},
destination: {
@@ -232,82 +241,84 @@ export const buildCanvasSDXLImageToImageGraph = (
field: 'latents',
},
},
// Decode denoised latents to an image
],
};
// Decode Latents To Image & Handle Scaled Before Processing
if (isUsingScaledDimensions) {
graph.nodes[IMG2IMG_RESIZE] = {
id: IMG2IMG_RESIZE,
type: 'img_resize',
is_intermediate: true,
image: initialImage,
width: scaledBoundingBoxDimensions.width,
height: scaledBoundingBoxDimensions.height,
};
graph.nodes[LATENTS_TO_IMAGE] = {
id: LATENTS_TO_IMAGE,
type: 'l2i',
is_intermediate: true,
fp32: vaePrecision === 'fp32' ? true : false,
};
graph.nodes[CANVAS_OUTPUT] = {
id: CANVAS_OUTPUT,
type: 'img_resize',
is_intermediate: !shouldAutoSave,
width: width,
height: height,
};
graph.edges.push(
{
source: {
node_id: IMG2IMG_RESIZE,
field: 'image',
},
destination: {
node_id: IMAGE_TO_LATENTS,
field: 'image',
},
},
{
source: {
node_id: SDXL_DENOISE_LATENTS,
field: 'latents',
},
destination: {
node_id: CANVAS_OUTPUT,
node_id: LATENTS_TO_IMAGE,
field: 'latents',
},
},
],
};
// handle `fit`
if (initialImage.width !== width || initialImage.height !== height) {
// The init image needs to be resized to the specified width and height before being passed to `IMAGE_TO_LATENTS`
// Create a resize node, explicitly setting its image
const resizeNode: ImageResizeInvocation = {
id: RESIZE,
type: 'img_resize',
image: {
image_name: initialImage.image_name,
},
is_intermediate: true,
width,
height,
};
graph.nodes[RESIZE] = resizeNode;
// The `RESIZE` node then passes its image to `IMAGE_TO_LATENTS`
graph.edges.push({
source: { node_id: RESIZE, field: 'image' },
destination: {
node_id: IMAGE_TO_LATENTS,
field: 'image',
},
});
// The `RESIZE` node also passes its width and height to `NOISE`
graph.edges.push({
source: { node_id: RESIZE, field: 'width' },
destination: {
node_id: NOISE,
field: 'width',
},
});
graph.edges.push({
source: { node_id: RESIZE, field: 'height' },
destination: {
node_id: NOISE,
field: 'height',
},
});
{
source: {
node_id: LATENTS_TO_IMAGE,
field: 'image',
},
destination: {
node_id: CANVAS_OUTPUT,
field: 'image',
},
}
);
} else {
// We are not resizing, so we need to set the image on the `IMAGE_TO_LATENTS` node explicitly
(graph.nodes[IMAGE_TO_LATENTS] as ImageToLatentsInvocation).image = {
image_name: initialImage.image_name,
graph.nodes[CANVAS_OUTPUT] = {
type: 'l2i',
id: CANVAS_OUTPUT,
is_intermediate: !shouldAutoSave,
fp32: vaePrecision === 'fp32' ? true : false,
};
// Pass the image's dimensions to the `NOISE` node
(graph.nodes[IMAGE_TO_LATENTS] as ImageToLatentsInvocation).image =
initialImage;
graph.edges.push({
source: { node_id: IMAGE_TO_LATENTS, field: 'width' },
destination: {
node_id: NOISE,
field: 'width',
source: {
node_id: SDXL_DENOISE_LATENTS,
field: 'latents',
},
});
graph.edges.push({
source: { node_id: IMAGE_TO_LATENTS, field: 'height' },
destination: {
node_id: NOISE,
field: 'height',
node_id: CANVAS_OUTPUT,
field: 'latents',
},
});
}
@@ -318,8 +329,10 @@ export const buildCanvasSDXLImageToImageGraph = (
type: 'metadata_accumulator',
generation_mode: 'img2img',
cfg_scale,
height,
width,
width: !isUsingScaledDimensions ? width : scaledBoundingBoxDimensions.width,
height: !isUsingScaledDimensions
? height
: scaledBoundingBoxDimensions.height,
positive_prompt: '', // set in addDynamicPromptsToGraph
negative_prompt: negativePrompt,
model,
@@ -346,16 +359,23 @@ export const buildCanvasSDXLImageToImageGraph = (
},
});
// add LoRA support
addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER);
// Add Seamless To Graph
if (seamlessXAxis || seamlessYAxis) {
addSeamlessToLinearGraph(state, graph, modelLoaderNodeId);
modelLoaderNodeId = SEAMLESS;
}
// Add Refiner if enabled
if (shouldUseSDXLRefiner) {
addSDXLRefinerToGraph(state, graph, SDXL_DENOISE_LATENTS);
modelLoaderNodeId = REFINER_SEAMLESS;
}
// optionally add custom VAE
addVAEToGraph(state, graph, SDXL_MODEL_LOADER);
addVAEToGraph(state, graph, modelLoaderNodeId);
// add LoRA support
addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, modelLoaderNodeId);
// add dynamic prompts - also sets up core iteration and seed
addDynamicPromptsToGraph(state, graph);

View File

@@ -2,6 +2,7 @@ import { logger } from 'app/logging/logger';
import { RootState } from 'app/store/store';
import { NonNullableGraph } from 'features/nodes/types/types';
import {
CreateDenoiseMaskInvocation,
ImageBlurInvocation,
ImageDTO,
ImageToLatentsInvocation,
@@ -13,13 +14,15 @@ import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
CANVAS_OUTPUT,
CANVAS_COHERENCE_DENOISE_LATENTS,
CANVAS_COHERENCE_NOISE,
CANVAS_COHERENCE_NOISE_INCREMENT,
CANVAS_OUTPUT,
INPAINT_CREATE_MASK,
INPAINT_IMAGE,
INPAINT_IMAGE_RESIZE_DOWN,
INPAINT_IMAGE_RESIZE_UP,
@@ -33,9 +36,11 @@ import {
POSITIVE_CONDITIONING,
RANDOM_INT,
RANGE_OF_SIZE,
REFINER_SEAMLESS,
SDXL_CANVAS_INPAINT_GRAPH,
SDXL_DENOISE_LATENTS,
SDXL_MODEL_LOADER,
SEAMLESS,
} from './constants';
import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt';
@@ -65,6 +70,8 @@ export const buildCanvasSDXLInpaintGraph = (
maskBlurMethod,
canvasCoherenceSteps,
canvasCoherenceStrength,
seamlessXAxis,
seamlessYAxis,
} = state.generation;
const {
@@ -89,6 +96,8 @@ export const buildCanvasSDXLInpaintGraph = (
shouldAutoSave,
} = state.canvas;
let modelLoaderNodeId = SDXL_MODEL_LOADER;
const use_cpu = shouldUseNoiseSettings
? shouldUseCpuNoise
: shouldUseCpuNoise;
@@ -100,9 +109,9 @@ export const buildCanvasSDXLInpaintGraph = (
const graph: NonNullableGraph = {
id: SDXL_CANVAS_INPAINT_GRAPH,
nodes: {
[SDXL_MODEL_LOADER]: {
[modelLoaderNodeId]: {
type: 'sdxl_model_loader',
id: SDXL_MODEL_LOADER,
id: modelLoaderNodeId,
model,
},
[POSITIVE_CONDITIONING]: {
@@ -136,6 +145,12 @@ export const buildCanvasSDXLInpaintGraph = (
use_cpu,
is_intermediate: true,
},
[INPAINT_CREATE_MASK]: {
type: 'create_denoise_mask',
id: INPAINT_CREATE_MASK,
is_intermediate: true,
fp32: vaePrecision === 'fp32' ? true : false,
},
[SDXL_DENOISE_LATENTS]: {
type: 'denoise_latents',
id: SDXL_DENOISE_LATENTS,
@@ -201,7 +216,7 @@ export const buildCanvasSDXLInpaintGraph = (
// Connect Model Loader to UNet and CLIP
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'unet',
},
destination: {
@@ -211,7 +226,7 @@ export const buildCanvasSDXLInpaintGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip',
},
destination: {
@@ -221,7 +236,7 @@ export const buildCanvasSDXLInpaintGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip2',
},
destination: {
@@ -231,7 +246,7 @@ export const buildCanvasSDXLInpaintGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip',
},
destination: {
@@ -241,7 +256,7 @@ export const buildCanvasSDXLInpaintGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip2',
},
destination: {
@@ -290,16 +305,27 @@ export const buildCanvasSDXLInpaintGraph = (
field: 'latents',
},
},
// Create Inpaint Mask
{
source: {
node_id: MASK_BLUR,
field: 'image',
},
destination: {
node_id: SDXL_DENOISE_LATENTS,
node_id: INPAINT_CREATE_MASK,
field: 'mask',
},
},
{
source: {
node_id: INPAINT_CREATE_MASK,
field: 'denoise_mask',
},
destination: {
node_id: SDXL_DENOISE_LATENTS,
field: 'denoise_mask',
},
},
// Iterate
{
source: {
@@ -344,7 +370,7 @@ export const buildCanvasSDXLInpaintGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'unet',
},
destination: {
@@ -473,6 +499,16 @@ export const buildCanvasSDXLInpaintGraph = (
field: 'image',
},
},
{
source: {
node_id: INPAINT_IMAGE_RESIZE_UP,
field: 'image',
},
destination: {
node_id: INPAINT_CREATE_MASK,
field: 'image',
},
},
// Color Correct The Inpainted Result
{
source: {
@@ -530,6 +566,10 @@ export const buildCanvasSDXLInpaintGraph = (
...(graph.nodes[MASK_BLUR] as ImageBlurInvocation),
image: canvasMaskImage,
};
graph.nodes[INPAINT_CREATE_MASK] = {
...(graph.nodes[INPAINT_CREATE_MASK] as CreateDenoiseMaskInvocation),
image: canvasInitImage,
};
graph.edges.push(
// Color Correct The Inpainted Result
@@ -576,16 +616,28 @@ export const buildCanvasSDXLInpaintGraph = (
(graph.nodes[RANGE_OF_SIZE] as RangeOfSizeInvocation).start = seed;
}
// Add Seamless To Graph
if (seamlessXAxis || seamlessYAxis) {
addSeamlessToLinearGraph(state, graph, modelLoaderNodeId);
modelLoaderNodeId = SEAMLESS;
}
// Add Refiner if enabled
if (shouldUseSDXLRefiner) {
addSDXLRefinerToGraph(state, graph, CANVAS_COHERENCE_DENOISE_LATENTS);
addSDXLRefinerToGraph(
state,
graph,
CANVAS_COHERENCE_DENOISE_LATENTS,
modelLoaderNodeId
);
modelLoaderNodeId = REFINER_SEAMLESS;
}
// optionally add custom VAE
addVAEToGraph(state, graph, SDXL_MODEL_LOADER);
addVAEToGraph(state, graph, modelLoaderNodeId);
// add LoRA support
addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER);
addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, modelLoaderNodeId);
// add controlnet, mutating `graph`
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);

View File

@@ -15,13 +15,15 @@ import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
CANVAS_OUTPUT,
CANVAS_COHERENCE_DENOISE_LATENTS,
CANVAS_COHERENCE_NOISE,
CANVAS_COHERENCE_NOISE_INCREMENT,
CANVAS_OUTPUT,
INPAINT_CREATE_MASK,
INPAINT_IMAGE,
INPAINT_IMAGE_RESIZE_DOWN,
INPAINT_IMAGE_RESIZE_UP,
@@ -39,9 +41,11 @@ import {
POSITIVE_CONDITIONING,
RANDOM_INT,
RANGE_OF_SIZE,
REFINER_SEAMLESS,
SDXL_CANVAS_OUTPAINT_GRAPH,
SDXL_DENOISE_LATENTS,
SDXL_MODEL_LOADER,
SEAMLESS,
} from './constants';
import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt';
@@ -73,6 +77,8 @@ export const buildCanvasSDXLOutpaintGraph = (
canvasCoherenceStrength,
tileSize,
infillMethod,
seamlessXAxis,
seamlessYAxis,
} = state.generation;
const {
@@ -97,6 +103,8 @@ export const buildCanvasSDXLOutpaintGraph = (
shouldAutoSave,
} = state.canvas;
let modelLoaderNodeId = SDXL_MODEL_LOADER;
const use_cpu = shouldUseNoiseSettings
? shouldUseCpuNoise
: shouldUseCpuNoise;
@@ -156,6 +164,12 @@ export const buildCanvasSDXLOutpaintGraph = (
use_cpu,
is_intermediate: true,
},
[INPAINT_CREATE_MASK]: {
type: 'create_denoise_mask',
id: INPAINT_CREATE_MASK,
is_intermediate: true,
fp32: vaePrecision === 'fp32' ? true : false,
},
[SDXL_DENOISE_LATENTS]: {
type: 'denoise_latents',
id: SDXL_DENOISE_LATENTS,
@@ -331,16 +345,27 @@ export const buildCanvasSDXLOutpaintGraph = (
field: 'latents',
},
},
// Create Inpaint Mask
{
source: {
node_id: MASK_BLUR,
field: 'image',
},
destination: {
node_id: SDXL_DENOISE_LATENTS,
node_id: INPAINT_CREATE_MASK,
field: 'mask',
},
},
{
source: {
node_id: INPAINT_CREATE_MASK,
field: 'denoise_mask',
},
destination: {
node_id: SDXL_DENOISE_LATENTS,
field: 'denoise_mask',
},
},
// Iterate
{
source: {
@@ -537,6 +562,16 @@ export const buildCanvasSDXLOutpaintGraph = (
field: 'image',
},
},
{
source: {
node_id: INPAINT_INFILL,
field: 'image',
},
destination: {
node_id: INPAINT_CREATE_MASK,
field: 'image',
},
},
// Take combined mask and resize and then blur
{
source: {
@@ -655,6 +690,16 @@ export const buildCanvasSDXLOutpaintGraph = (
field: 'image',
},
},
{
source: {
node_id: INPAINT_INFILL,
field: 'image',
},
destination: {
node_id: INPAINT_CREATE_MASK,
field: 'image',
},
},
// Color Correct The Inpainted Result
{
source: {
@@ -709,16 +754,28 @@ export const buildCanvasSDXLOutpaintGraph = (
(graph.nodes[RANGE_OF_SIZE] as RangeOfSizeInvocation).start = seed;
}
// Add Seamless To Graph
if (seamlessXAxis || seamlessYAxis) {
addSeamlessToLinearGraph(state, graph, modelLoaderNodeId);
modelLoaderNodeId = SEAMLESS;
}
// Add Refiner if enabled
if (shouldUseSDXLRefiner) {
addSDXLRefinerToGraph(state, graph, CANVAS_COHERENCE_DENOISE_LATENTS);
addSDXLRefinerToGraph(
state,
graph,
CANVAS_COHERENCE_DENOISE_LATENTS,
modelLoaderNodeId
);
modelLoaderNodeId = REFINER_SEAMLESS;
}
// optionally add custom VAE
addVAEToGraph(state, graph, SDXL_MODEL_LOADER);
addVAEToGraph(state, graph, modelLoaderNodeId);
// add LoRA support
addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER);
addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, modelLoaderNodeId);
// add controlnet, mutating `graph`
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);

View File

@@ -11,18 +11,22 @@ import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
CANVAS_OUTPUT,
LATENTS_TO_IMAGE,
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
NOISE,
ONNX_MODEL_LOADER,
POSITIVE_CONDITIONING,
REFINER_SEAMLESS,
SDXL_CANVAS_TEXT_TO_IMAGE_GRAPH,
SDXL_DENOISE_LATENTS,
SDXL_MODEL_LOADER,
SEAMLESS,
} from './constants';
import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt';
@@ -44,12 +48,22 @@ export const buildCanvasSDXLTextToImageGraph = (
clipSkip,
shouldUseCpuNoise,
shouldUseNoiseSettings,
seamlessXAxis,
seamlessYAxis,
} = state.generation;
// The bounding box determines width and height, not the width and height params
const { width, height } = state.canvas.boundingBoxDimensions;
const { shouldAutoSave } = state.canvas;
const {
scaledBoundingBoxDimensions,
boundingBoxScaleMethod,
shouldAutoSave,
} = state.canvas;
const isUsingScaledDimensions = ['auto', 'manual'].includes(
boundingBoxScaleMethod
);
const { shouldUseSDXLRefiner, refinerStart, shouldConcatSDXLStylePrompt } =
state.sdxl;
@@ -65,7 +79,7 @@ export const buildCanvasSDXLTextToImageGraph = (
const isUsingOnnxModel = model.model_type === 'onnx';
const modelLoaderNodeId = isUsingOnnxModel
let modelLoaderNodeId = isUsingOnnxModel
? ONNX_MODEL_LOADER
: SDXL_MODEL_LOADER;
@@ -136,17 +150,15 @@ export const buildCanvasSDXLTextToImageGraph = (
type: 'noise',
id: NOISE,
is_intermediate: true,
width,
height,
width: !isUsingScaledDimensions
? width
: scaledBoundingBoxDimensions.width,
height: !isUsingScaledDimensions
? height
: scaledBoundingBoxDimensions.height,
use_cpu,
},
[t2lNode.id]: t2lNode,
[CANVAS_OUTPUT]: {
type: isUsingOnnxModel ? 'l2i_onnx' : 'l2i',
id: CANVAS_OUTPUT,
is_intermediate: !shouldAutoSave,
fp32: vaePrecision === 'fp32' ? true : false,
},
},
edges: [
// Connect Model Loader to UNet and CLIP
@@ -231,19 +243,67 @@ export const buildCanvasSDXLTextToImageGraph = (
field: 'noise',
},
},
// Decode Denoised Latents To Image
],
};
// Decode Latents To Image & Handle Scaled Before Processing
if (isUsingScaledDimensions) {
graph.nodes[LATENTS_TO_IMAGE] = {
id: LATENTS_TO_IMAGE,
type: isUsingOnnxModel ? 'l2i_onnx' : 'l2i',
is_intermediate: true,
fp32: vaePrecision === 'fp32' ? true : false,
};
graph.nodes[CANVAS_OUTPUT] = {
id: CANVAS_OUTPUT,
type: 'img_resize',
is_intermediate: !shouldAutoSave,
width: width,
height: height,
};
graph.edges.push(
{
source: {
node_id: SDXL_DENOISE_LATENTS,
field: 'latents',
},
destination: {
node_id: CANVAS_OUTPUT,
node_id: LATENTS_TO_IMAGE,
field: 'latents',
},
},
],
};
{
source: {
node_id: LATENTS_TO_IMAGE,
field: 'image',
},
destination: {
node_id: CANVAS_OUTPUT,
field: 'image',
},
}
);
} else {
graph.nodes[CANVAS_OUTPUT] = {
type: isUsingOnnxModel ? 'l2i_onnx' : 'l2i',
id: CANVAS_OUTPUT,
is_intermediate: !shouldAutoSave,
fp32: vaePrecision === 'fp32' ? true : false,
};
graph.edges.push({
source: {
node_id: SDXL_DENOISE_LATENTS,
field: 'latents',
},
destination: {
node_id: CANVAS_OUTPUT,
field: 'latents',
},
});
}
// add metadata accumulator, which is only mostly populated - some fields are added later
graph.nodes[METADATA_ACCUMULATOR] = {
@@ -251,8 +311,10 @@ export const buildCanvasSDXLTextToImageGraph = (
type: 'metadata_accumulator',
generation_mode: 'txt2img',
cfg_scale,
height,
width,
width: !isUsingScaledDimensions ? width : scaledBoundingBoxDimensions.width,
height: !isUsingScaledDimensions
? height
: scaledBoundingBoxDimensions.height,
positive_prompt: '', // set in addDynamicPromptsToGraph
negative_prompt: negativePrompt,
model,
@@ -277,9 +339,16 @@ export const buildCanvasSDXLTextToImageGraph = (
},
});
// Add Seamless To Graph
if (seamlessXAxis || seamlessYAxis) {
addSeamlessToLinearGraph(state, graph, modelLoaderNodeId);
modelLoaderNodeId = SEAMLESS;
}
// Add Refiner if enabled
if (shouldUseSDXLRefiner) {
addSDXLRefinerToGraph(state, graph, SDXL_DENOISE_LATENTS);
modelLoaderNodeId = REFINER_SEAMLESS;
}
// add LoRA support

View File

@@ -10,6 +10,7 @@ import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
import { addLoRAsToGraph } from './addLoRAsToGraph';
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
@@ -17,12 +18,14 @@ import {
CANVAS_TEXT_TO_IMAGE_GRAPH,
CLIP_SKIP,
DENOISE_LATENTS,
LATENTS_TO_IMAGE,
MAIN_MODEL_LOADER,
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
NOISE,
ONNX_MODEL_LOADER,
POSITIVE_CONDITIONING,
SEAMLESS,
} from './constants';
/**
@@ -39,15 +42,26 @@ export const buildCanvasTextToImageGraph = (
cfgScale: cfg_scale,
scheduler,
steps,
vaePrecision,
clipSkip,
shouldUseCpuNoise,
shouldUseNoiseSettings,
seamlessXAxis,
seamlessYAxis,
} = state.generation;
// The bounding box determines width and height, not the width and height params
const { width, height } = state.canvas.boundingBoxDimensions;
const { shouldAutoSave } = state.canvas;
const {
scaledBoundingBoxDimensions,
boundingBoxScaleMethod,
shouldAutoSave,
} = state.canvas;
const isUsingScaledDimensions = ['auto', 'manual'].includes(
boundingBoxScaleMethod
);
if (!model) {
log.error('No model found in state');
@@ -60,7 +74,7 @@ export const buildCanvasTextToImageGraph = (
const isUsingOnnxModel = model.model_type === 'onnx';
const modelLoaderNodeId = isUsingOnnxModel
let modelLoaderNodeId = isUsingOnnxModel
? ONNX_MODEL_LOADER
: MAIN_MODEL_LOADER;
@@ -131,16 +145,15 @@ export const buildCanvasTextToImageGraph = (
type: 'noise',
id: NOISE,
is_intermediate: true,
width,
height,
width: !isUsingScaledDimensions
? width
: scaledBoundingBoxDimensions.width,
height: !isUsingScaledDimensions
? height
: scaledBoundingBoxDimensions.height,
use_cpu,
},
[t2lNode.id]: t2lNode,
[CANVAS_OUTPUT]: {
type: isUsingOnnxModel ? 'l2i_onnx' : 'l2i',
id: CANVAS_OUTPUT,
is_intermediate: !shouldAutoSave,
},
},
edges: [
// Connect Model Loader to UNet & CLIP Skip
@@ -216,19 +229,67 @@ export const buildCanvasTextToImageGraph = (
field: 'noise',
},
},
// Decode denoised latents to image
],
};
// Decode Latents To Image & Handle Scaled Before Processing
if (isUsingScaledDimensions) {
graph.nodes[LATENTS_TO_IMAGE] = {
id: LATENTS_TO_IMAGE,
type: isUsingOnnxModel ? 'l2i_onnx' : 'l2i',
is_intermediate: true,
fp32: vaePrecision === 'fp32' ? true : false,
};
graph.nodes[CANVAS_OUTPUT] = {
id: CANVAS_OUTPUT,
type: 'img_resize',
is_intermediate: !shouldAutoSave,
width: width,
height: height,
};
graph.edges.push(
{
source: {
node_id: DENOISE_LATENTS,
field: 'latents',
},
destination: {
node_id: CANVAS_OUTPUT,
node_id: LATENTS_TO_IMAGE,
field: 'latents',
},
},
],
};
{
source: {
node_id: LATENTS_TO_IMAGE,
field: 'image',
},
destination: {
node_id: CANVAS_OUTPUT,
field: 'image',
},
}
);
} else {
graph.nodes[CANVAS_OUTPUT] = {
type: isUsingOnnxModel ? 'l2i_onnx' : 'l2i',
id: CANVAS_OUTPUT,
is_intermediate: !shouldAutoSave,
fp32: vaePrecision === 'fp32' ? true : false,
};
graph.edges.push({
source: {
node_id: DENOISE_LATENTS,
field: 'latents',
},
destination: {
node_id: CANVAS_OUTPUT,
field: 'latents',
},
});
}
// add metadata accumulator, which is only mostly populated - some fields are added later
graph.nodes[METADATA_ACCUMULATOR] = {
@@ -236,8 +297,10 @@ export const buildCanvasTextToImageGraph = (
type: 'metadata_accumulator',
generation_mode: 'txt2img',
cfg_scale,
height,
width,
width: !isUsingScaledDimensions ? width : scaledBoundingBoxDimensions.width,
height: !isUsingScaledDimensions
? height
: scaledBoundingBoxDimensions.height,
positive_prompt: '', // set in addDynamicPromptsToGraph
negative_prompt: negativePrompt,
model,
@@ -262,6 +325,12 @@ export const buildCanvasTextToImageGraph = (
},
});
// Add Seamless To Graph
if (seamlessXAxis || seamlessYAxis) {
addSeamlessToLinearGraph(state, graph, modelLoaderNodeId);
modelLoaderNodeId = SEAMLESS;
}
// optionally add custom VAE
addVAEToGraph(state, graph, modelLoaderNodeId);

View File

@@ -10,6 +10,7 @@ import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
import { addLoRAsToGraph } from './addLoRAsToGraph';
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
@@ -24,6 +25,7 @@ import {
NOISE,
POSITIVE_CONDITIONING,
RESIZE,
SEAMLESS,
} from './constants';
/**
@@ -49,6 +51,8 @@ export const buildLinearImageToImageGraph = (
shouldUseCpuNoise,
shouldUseNoiseSettings,
vaePrecision,
seamlessXAxis,
seamlessYAxis,
} = state.generation;
// TODO: add batch functionality
@@ -80,6 +84,8 @@ export const buildLinearImageToImageGraph = (
throw new Error('No model found in state');
}
let modelLoaderNodeId = MAIN_MODEL_LOADER;
const use_cpu = shouldUseNoiseSettings
? shouldUseCpuNoise
: initialGenerationState.shouldUseCpuNoise;
@@ -88,9 +94,9 @@ export const buildLinearImageToImageGraph = (
const graph: NonNullableGraph = {
id: IMAGE_TO_IMAGE_GRAPH,
nodes: {
[MAIN_MODEL_LOADER]: {
[modelLoaderNodeId]: {
type: 'main_model_loader',
id: MAIN_MODEL_LOADER,
id: modelLoaderNodeId,
model,
},
[CLIP_SKIP]: {
@@ -141,7 +147,7 @@ export const buildLinearImageToImageGraph = (
// Connect Model Loader to UNet and CLIP Skip
{
source: {
node_id: MAIN_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'unet',
},
destination: {
@@ -151,7 +157,7 @@ export const buildLinearImageToImageGraph = (
},
{
source: {
node_id: MAIN_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip',
},
destination: {
@@ -338,11 +344,17 @@ export const buildLinearImageToImageGraph = (
},
});
// Add Seamless To Graph
if (seamlessXAxis || seamlessYAxis) {
addSeamlessToLinearGraph(state, graph, modelLoaderNodeId);
modelLoaderNodeId = SEAMLESS;
}
// optionally add custom VAE
addVAEToGraph(state, graph, MAIN_MODEL_LOADER);
addVAEToGraph(state, graph, modelLoaderNodeId);
// add LoRA support
addLoRAsToGraph(state, graph, DENOISE_LATENTS);
addLoRAsToGraph(state, graph, DENOISE_LATENTS, modelLoaderNodeId);
// add dynamic prompts - also sets up core iteration and seed
addDynamicPromptsToGraph(state, graph);

View File

@@ -11,6 +11,7 @@ import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
@@ -20,10 +21,12 @@ import {
NEGATIVE_CONDITIONING,
NOISE,
POSITIVE_CONDITIONING,
REFINER_SEAMLESS,
RESIZE,
SDXL_DENOISE_LATENTS,
SDXL_IMAGE_TO_IMAGE_GRAPH,
SDXL_MODEL_LOADER,
SEAMLESS,
} from './constants';
import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt';
@@ -49,6 +52,8 @@ export const buildLinearSDXLImageToImageGraph = (
shouldUseCpuNoise,
shouldUseNoiseSettings,
vaePrecision,
seamlessXAxis,
seamlessYAxis,
} = state.generation;
const {
@@ -79,6 +84,9 @@ export const buildLinearSDXLImageToImageGraph = (
throw new Error('No model found in state');
}
// Model Loader ID
let modelLoaderNodeId = SDXL_MODEL_LOADER;
const use_cpu = shouldUseNoiseSettings
? shouldUseCpuNoise
: initialGenerationState.shouldUseCpuNoise;
@@ -91,9 +99,9 @@ export const buildLinearSDXLImageToImageGraph = (
const graph: NonNullableGraph = {
id: SDXL_IMAGE_TO_IMAGE_GRAPH,
nodes: {
[SDXL_MODEL_LOADER]: {
[modelLoaderNodeId]: {
type: 'sdxl_model_loader',
id: SDXL_MODEL_LOADER,
id: modelLoaderNodeId,
model,
},
[POSITIVE_CONDITIONING]: {
@@ -143,7 +151,7 @@ export const buildLinearSDXLImageToImageGraph = (
// Connect Model Loader to UNet, CLIP & VAE
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'unet',
},
destination: {
@@ -153,7 +161,7 @@ export const buildLinearSDXLImageToImageGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip',
},
destination: {
@@ -163,7 +171,7 @@ export const buildLinearSDXLImageToImageGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip2',
},
destination: {
@@ -173,7 +181,7 @@ export const buildLinearSDXLImageToImageGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip',
},
destination: {
@@ -183,7 +191,7 @@ export const buildLinearSDXLImageToImageGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip2',
},
destination: {
@@ -351,15 +359,23 @@ export const buildLinearSDXLImageToImageGraph = (
},
});
addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER);
// Add Seamless To Graph
if (seamlessXAxis || seamlessYAxis) {
addSeamlessToLinearGraph(state, graph, modelLoaderNodeId);
modelLoaderNodeId = SEAMLESS;
}
// Add Refiner if enabled
if (shouldUseSDXLRefiner) {
addSDXLRefinerToGraph(state, graph, SDXL_DENOISE_LATENTS);
modelLoaderNodeId = REFINER_SEAMLESS;
}
// optionally add custom VAE
addVAEToGraph(state, graph, SDXL_MODEL_LOADER);
addVAEToGraph(state, graph, modelLoaderNodeId);
// Add LoRA Support
addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, modelLoaderNodeId);
// add controlnet, mutating `graph`
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);

View File

@@ -7,6 +7,7 @@ import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
@@ -15,9 +16,11 @@ import {
NEGATIVE_CONDITIONING,
NOISE,
POSITIVE_CONDITIONING,
REFINER_SEAMLESS,
SDXL_DENOISE_LATENTS,
SDXL_MODEL_LOADER,
SDXL_TEXT_TO_IMAGE_GRAPH,
SEAMLESS,
} from './constants';
import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt';
@@ -38,6 +41,8 @@ export const buildLinearSDXLTextToImageGraph = (
shouldUseCpuNoise,
shouldUseNoiseSettings,
vaePrecision,
seamlessXAxis,
seamlessYAxis,
} = state.generation;
const {
@@ -61,6 +66,9 @@ export const buildLinearSDXLTextToImageGraph = (
const { craftedPositiveStylePrompt, craftedNegativeStylePrompt } =
craftSDXLStylePrompt(state, shouldConcatSDXLStylePrompt);
// Model Loader ID
let modelLoaderNodeId = SDXL_MODEL_LOADER;
/**
* The easiest way to build linear graphs is to do it in the node editor, then copy and paste the
* full graph here as a template. Then use the parameters from app state and set friendlier node
@@ -74,9 +82,9 @@ export const buildLinearSDXLTextToImageGraph = (
const graph: NonNullableGraph = {
id: SDXL_TEXT_TO_IMAGE_GRAPH,
nodes: {
[SDXL_MODEL_LOADER]: {
[modelLoaderNodeId]: {
type: 'sdxl_model_loader',
id: SDXL_MODEL_LOADER,
id: modelLoaderNodeId,
model,
},
[POSITIVE_CONDITIONING]: {
@@ -117,7 +125,7 @@ export const buildLinearSDXLTextToImageGraph = (
// Connect Model Loader to UNet, VAE & CLIP
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'unet',
},
destination: {
@@ -127,7 +135,7 @@ export const buildLinearSDXLTextToImageGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip',
},
destination: {
@@ -137,7 +145,7 @@ export const buildLinearSDXLTextToImageGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip2',
},
destination: {
@@ -147,7 +155,7 @@ export const buildLinearSDXLTextToImageGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip',
},
destination: {
@@ -157,7 +165,7 @@ export const buildLinearSDXLTextToImageGraph = (
},
{
source: {
node_id: SDXL_MODEL_LOADER,
node_id: modelLoaderNodeId,
field: 'clip2',
},
destination: {
@@ -244,16 +252,23 @@ export const buildLinearSDXLTextToImageGraph = (
},
});
// Add Seamless To Graph
if (seamlessXAxis || seamlessYAxis) {
addSeamlessToLinearGraph(state, graph, modelLoaderNodeId);
modelLoaderNodeId = SEAMLESS;
}
// Add Refiner if enabled
if (shouldUseSDXLRefiner) {
addSDXLRefinerToGraph(state, graph, SDXL_DENOISE_LATENTS);
modelLoaderNodeId = REFINER_SEAMLESS;
}
// optionally add custom VAE
addVAEToGraph(state, graph, SDXL_MODEL_LOADER);
addVAEToGraph(state, graph, modelLoaderNodeId);
// add LoRA support
addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, SDXL_MODEL_LOADER);
addSDXLLoRAsToGraph(state, graph, SDXL_DENOISE_LATENTS, modelLoaderNodeId);
// add controlnet, mutating `graph`
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);

View File

@@ -10,6 +10,7 @@ import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
import { addLoRAsToGraph } from './addLoRAsToGraph';
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
@@ -22,6 +23,7 @@ import {
NOISE,
ONNX_MODEL_LOADER,
POSITIVE_CONDITIONING,
SEAMLESS,
TEXT_TO_IMAGE_GRAPH,
} from './constants';
@@ -42,6 +44,8 @@ export const buildLinearTextToImageGraph = (
shouldUseCpuNoise,
shouldUseNoiseSettings,
vaePrecision,
seamlessXAxis,
seamlessYAxis,
} = state.generation;
const use_cpu = shouldUseNoiseSettings
@@ -55,7 +59,7 @@ export const buildLinearTextToImageGraph = (
const isUsingOnnxModel = model.model_type === 'onnx';
const modelLoaderNodeId = isUsingOnnxModel
let modelLoaderNodeId = isUsingOnnxModel
? ONNX_MODEL_LOADER
: MAIN_MODEL_LOADER;
@@ -258,6 +262,12 @@ export const buildLinearTextToImageGraph = (
},
});
// Add Seamless To Graph
if (seamlessXAxis || seamlessYAxis) {
addSeamlessToLinearGraph(state, graph, modelLoaderNodeId);
modelLoaderNodeId = SEAMLESS;
}
// optionally add custom VAE
addVAEToGraph(state, graph, modelLoaderNodeId);

View File

@@ -17,6 +17,7 @@ export const CLIP_SKIP = 'clip_skip';
export const IMAGE_TO_LATENTS = 'image_to_latents';
export const LATENTS_TO_LATENTS = 'latents_to_latents';
export const RESIZE = 'resize_image';
export const IMG2IMG_RESIZE = 'img2img_resize';
export const CANVAS_OUTPUT = 'canvas_output';
export const INPAINT_IMAGE = 'inpaint_image';
export const SCALED_INPAINT_IMAGE = 'scaled_inpaint_image';
@@ -25,6 +26,7 @@ export const INPAINT_IMAGE_RESIZE_DOWN = 'inpaint_image_resize_down';
export const INPAINT_INFILL = 'inpaint_infill';
export const INPAINT_INFILL_RESIZE_DOWN = 'inpaint_infill_resize_down';
export const INPAINT_FINAL_IMAGE = 'inpaint_final_image';
export const INPAINT_CREATE_MASK = 'inpaint_create_mask';
export const CANVAS_COHERENCE_DENOISE_LATENTS =
'canvas_coherence_denoise_latents';
export const CANVAS_COHERENCE_NOISE = 'canvas_coherence_noise';
@@ -54,6 +56,8 @@ export const SDXL_REFINER_POSITIVE_CONDITIONING =
export const SDXL_REFINER_NEGATIVE_CONDITIONING =
'sdxl_refiner_negative_conditioning';
export const SDXL_REFINER_DENOISE_LATENTS = 'sdxl_refiner_denoise_latents';
export const SEAMLESS = 'seamless';
export const REFINER_SEAMLESS = 'refiner_seamless';
// friendly graph ids
export const TEXT_TO_IMAGE_GRAPH = 'text_to_image_graph';

View File

@@ -0,0 +1,81 @@
import { skipToken } from '@reduxjs/toolkit/dist/query';
import { t } from 'i18next';
import { useCallback, useState } from 'react';
import { useAppToaster } from '../../../app/components/Toaster';
import { useAppDispatch } from '../../../app/store/storeHooks';
import {
useGetImageDTOQuery,
useGetImageMetadataQuery,
} from '../../../services/api/endpoints/images';
import { setInitialCanvasImage } from '../../canvas/store/canvasSlice';
import { setActiveTab } from '../../ui/store/uiSlice';
import { initialImageSelected } from '../store/actions';
import { useRecallParameters } from './useRecallParameters';
type SelectedImage = {
imageName: string;
action: 'sendToImg2Img' | 'sendToCanvas' | 'useAllParameters';
};
export const usePreselectedImage = () => {
const dispatch = useAppDispatch();
const [imageNameForDto, setImageNameForDto] = useState<string | undefined>();
const [imageNameForMetadata, setImageNameForMetadata] = useState<
string | undefined
>();
const { recallAllParameters } = useRecallParameters();
const toaster = useAppToaster();
const { currentData: selectedImageDto } = useGetImageDTOQuery(
imageNameForDto ?? skipToken
);
const { currentData: selectedImageMetadata } = useGetImageMetadataQuery(
imageNameForMetadata ?? skipToken
);
const handlePreselectedImage = useCallback(
(selectedImage?: SelectedImage) => {
if (!selectedImage) {
return;
}
if (selectedImage.action === 'sendToCanvas') {
setImageNameForDto(selectedImage?.imageName);
if (selectedImageDto) {
dispatch(setInitialCanvasImage(selectedImageDto));
dispatch(setActiveTab('unifiedCanvas'));
toaster({
title: t('toast.sentToUnifiedCanvas'),
status: 'info',
duration: 2500,
isClosable: true,
});
}
}
if (selectedImage.action === 'sendToImg2Img') {
setImageNameForDto(selectedImage?.imageName);
if (selectedImageDto) {
dispatch(initialImageSelected(selectedImageDto));
}
}
if (selectedImage.action === 'useAllParameters') {
setImageNameForMetadata(selectedImage?.imageName);
if (selectedImageMetadata) {
recallAllParameters(selectedImageMetadata.metadata);
}
}
},
[
dispatch,
selectedImageDto,
selectedImageMetadata,
recallAllParameters,
toaster,
]
);
return { handlePreselectedImage };
};

View File

@@ -2,6 +2,7 @@ import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/Para
import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse';
import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse';
import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse';
import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse';
import { memo } from 'react';
import ParamSDXLPromptArea from './ParamSDXLPromptArea';
import ParamSDXLRefinerCollapse from './ParamSDXLRefinerCollapse';
@@ -17,6 +18,7 @@ const SDXLImageToImageTabParameters = () => {
<ParamLoraCollapse />
<ParamDynamicPromptsCollapse />
<ParamNoiseCollapse />
<ParamSeamlessCollapse />
</>
);
};

View File

@@ -2,6 +2,7 @@ import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/Para
import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse';
import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse';
import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse';
import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse';
import TextToImageTabCoreParameters from 'features/ui/components/tabs/TextToImage/TextToImageTabCoreParameters';
import { memo } from 'react';
import ParamSDXLPromptArea from './ParamSDXLPromptArea';
@@ -17,6 +18,7 @@ const SDXLTextToImageTabParameters = () => {
<ParamLoraCollapse />
<ParamDynamicPromptsCollapse />
<ParamNoiseCollapse />
<ParamSeamlessCollapse />
</>
);
};

View File

@@ -5,6 +5,7 @@ import ParamMaskAdjustmentCollapse from 'features/parameters/components/Paramete
import ParamCanvasCoherencePassCollapse from 'features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherencePassCollapse';
import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse';
import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse';
import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse';
import ParamSDXLPromptArea from './ParamSDXLPromptArea';
import ParamSDXLRefinerCollapse from './ParamSDXLRefinerCollapse';
import SDXLUnifiedCanvasTabCoreParameters from './SDXLUnifiedCanvasTabCoreParameters';
@@ -22,6 +23,7 @@ export default function SDXLUnifiedCanvasTabParameters() {
<ParamMaskAdjustmentCollapse />
<ParamInfillAndScalingCollapse />
<ParamCanvasCoherencePassCollapse />
<ParamSeamlessCollapse />
</>
);
}

View File

@@ -9,7 +9,6 @@ export const initialConfigState: AppConfig = {
disabledFeatures: ['lightbox', 'faceRestore', 'batches'],
disabledSDFeatures: [
'variation',
'seamless',
'symmetry',
'hires',
'perlinNoise',

View File

@@ -6,6 +6,7 @@ import ParamMaskAdjustmentCollapse from 'features/parameters/components/Paramete
import ParamCanvasCoherencePassCollapse from 'features/parameters/components/Parameters/Canvas/SeamPainting/ParamCanvasCoherencePassCollapse';
import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse';
import ParamPromptArea from 'features/parameters/components/Parameters/Prompt/ParamPromptArea';
import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse';
import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse';
import { memo } from 'react';
import UnifiedCanvasCoreParameters from './UnifiedCanvasCoreParameters';
@@ -22,6 +23,7 @@ const UnifiedCanvasParameters = () => {
<ParamMaskAdjustmentCollapse />
<ParamInfillAndScalingCollapse />
<ParamCanvasCoherencePassCollapse />
<ParamSeamlessCollapse />
<ParamAdvancedCollapse />
</>
);

View File

@@ -111,6 +111,7 @@ export type ImageBlurInvocation = s['ImageBlurInvocation'];
export type ImageScaleInvocation = s['ImageScaleInvocation'];
export type InfillPatchMatchInvocation = s['InfillPatchMatchInvocation'];
export type InfillTileInvocation = s['InfillTileInvocation'];
export type CreateDenoiseMaskInvocation = s['CreateDenoiseMaskInvocation'];
export type RandomIntInvocation = s['RandomIntInvocation'];
export type CompelInvocation = s['CompelInvocation'];
export type DynamicPromptInvocation = s['DynamicPromptInvocation'];
@@ -129,6 +130,7 @@ export type ESRGANInvocation = s['ESRGANInvocation'];
export type DivideInvocation = s['DivideInvocation'];
export type ImageNSFWBlurInvocation = s['ImageNSFWBlurInvocation'];
export type ImageWatermarkInvocation = s['ImageWatermarkInvocation'];
export type SeamlessModeInvocation = s['SeamlessModeInvocation'];
// ControlNet Nodes
export type ControlNetInvocation = s['ControlNetInvocation'];