feat: metadata refactor

- Refactor how metadata is handled to support a user-defined metadata in graphs
- Update workflow embed handling
- Update UI to work with these changes
- Update tests to support metadata/workflow changes
This commit is contained in:
psychedelicious
2023-10-17 17:23:10 +11:00
parent c2da74c587
commit f0db4d36e4
66 changed files with 1807 additions and 1798 deletions

View File

@ -7,6 +7,7 @@ import {
startCase,
} from 'lodash-es';
import { OpenAPIV3_1 } from 'openapi-types';
import { ControlField } from 'services/api/types';
import {
COLLECTION_MAP,
POLYMORPHIC_TYPES,
@ -15,36 +16,70 @@ import {
isPolymorphicItemType,
} from '../types/constants';
import {
AnyInputFieldTemplate,
BoardInputFieldTemplate,
BooleanCollectionInputFieldTemplate,
BooleanInputFieldTemplate,
BooleanPolymorphicInputFieldTemplate,
ClipInputFieldTemplate,
CollectionInputFieldTemplate,
CollectionItemInputFieldTemplate,
ColorCollectionInputFieldTemplate,
ColorInputFieldTemplate,
ColorPolymorphicInputFieldTemplate,
ConditioningCollectionInputFieldTemplate,
ConditioningField,
ConditioningInputFieldTemplate,
ConditioningPolymorphicInputFieldTemplate,
ControlCollectionInputFieldTemplate,
ControlInputFieldTemplate,
ControlNetModelInputFieldTemplate,
ControlPolymorphicInputFieldTemplate,
DenoiseMaskInputFieldTemplate,
EnumInputFieldTemplate,
FieldType,
FloatCollectionInputFieldTemplate,
FloatPolymorphicInputFieldTemplate,
FloatInputFieldTemplate,
FloatPolymorphicInputFieldTemplate,
IPAdapterCollectionInputFieldTemplate,
IPAdapterField,
IPAdapterInputFieldTemplate,
IPAdapterModelInputFieldTemplate,
IPAdapterPolymorphicInputFieldTemplate,
ImageCollectionInputFieldTemplate,
ImageField,
ImageInputFieldTemplate,
ImagePolymorphicInputFieldTemplate,
InputFieldTemplate,
InputFieldTemplateBase,
IntegerCollectionInputFieldTemplate,
IntegerInputFieldTemplate,
IntegerPolymorphicInputFieldTemplate,
InvocationFieldSchema,
InvocationSchemaObject,
LatentsCollectionInputFieldTemplate,
LatentsField,
LatentsInputFieldTemplate,
LatentsPolymorphicInputFieldTemplate,
LoRAModelInputFieldTemplate,
MainModelInputFieldTemplate,
MetadataCollectionInputFieldTemplate,
MetadataInputFieldTemplate,
MetadataItemCollectionInputFieldTemplate,
MetadataItemInputFieldTemplate,
MetadataItemPolymorphicInputFieldTemplate,
OpenAPIV3_1SchemaOrRef,
SDXLMainModelInputFieldTemplate,
SDXLRefinerModelInputFieldTemplate,
SchedulerInputFieldTemplate,
StringCollectionInputFieldTemplate,
StringInputFieldTemplate,
StringPolymorphicInputFieldTemplate,
T2IAdapterCollectionInputFieldTemplate,
T2IAdapterField,
T2IAdapterInputFieldTemplate,
T2IAdapterModelInputFieldTemplate,
T2IAdapterPolymorphicInputFieldTemplate,
UNetInputFieldTemplate,
VaeInputFieldTemplate,
VaeModelInputFieldTemplate,
@ -52,36 +87,7 @@ import {
isNonArraySchemaObject,
isRefObject,
isSchemaObject,
ControlPolymorphicInputFieldTemplate,
ColorPolymorphicInputFieldTemplate,
ColorCollectionInputFieldTemplate,
IntegerPolymorphicInputFieldTemplate,
StringPolymorphicInputFieldTemplate,
BooleanPolymorphicInputFieldTemplate,
ImagePolymorphicInputFieldTemplate,
LatentsPolymorphicInputFieldTemplate,
LatentsCollectionInputFieldTemplate,
ConditioningPolymorphicInputFieldTemplate,
ConditioningCollectionInputFieldTemplate,
ControlCollectionInputFieldTemplate,
ImageField,
LatentsField,
ConditioningField,
IPAdapterField,
IPAdapterInputFieldTemplate,
IPAdapterModelInputFieldTemplate,
IPAdapterPolymorphicInputFieldTemplate,
IPAdapterCollectionInputFieldTemplate,
T2IAdapterField,
T2IAdapterInputFieldTemplate,
T2IAdapterModelInputFieldTemplate,
T2IAdapterPolymorphicInputFieldTemplate,
T2IAdapterCollectionInputFieldTemplate,
BoardInputFieldTemplate,
InputFieldTemplate,
OpenAPIV3_1SchemaOrRef,
} from '../types/types';
import { ControlField } from 'services/api/types';
export type BaseFieldProperties = 'name' | 'title' | 'description';
@ -851,6 +857,78 @@ const buildCollectionItemInputFieldTemplate = ({
return template;
};
const buildAnyInputFieldTemplate = ({
baseField,
}: BuildInputFieldArg): AnyInputFieldTemplate => {
const template: AnyInputFieldTemplate = {
...baseField,
type: 'Any',
default: undefined,
};
return template;
};
const buildMetadataItemInputFieldTemplate = ({
baseField,
}: BuildInputFieldArg): MetadataItemInputFieldTemplate => {
const template: MetadataItemInputFieldTemplate = {
...baseField,
type: 'MetadataItemField',
default: undefined,
};
return template;
};
const buildMetadataItemCollectionInputFieldTemplate = ({
baseField,
}: BuildInputFieldArg): MetadataItemCollectionInputFieldTemplate => {
const template: MetadataItemCollectionInputFieldTemplate = {
...baseField,
type: 'MetadataItemCollection',
default: undefined,
};
return template;
};
const buildMetadataItemPolymorphicInputFieldTemplate = ({
baseField,
}: BuildInputFieldArg): MetadataItemPolymorphicInputFieldTemplate => {
const template: MetadataItemPolymorphicInputFieldTemplate = {
...baseField,
type: 'MetadataItemPolymorphic',
default: undefined,
};
return template;
};
const buildMetadataDictInputFieldTemplate = ({
baseField,
}: BuildInputFieldArg): MetadataInputFieldTemplate => {
const template: MetadataInputFieldTemplate = {
...baseField,
type: 'MetadataField',
default: undefined,
};
return template;
};
const buildMetadataCollectionInputFieldTemplate = ({
baseField,
}: BuildInputFieldArg): MetadataCollectionInputFieldTemplate => {
const template: MetadataCollectionInputFieldTemplate = {
...baseField,
type: 'MetadataCollection',
default: undefined,
};
return template;
};
const buildColorInputFieldTemplate = ({
schemaObject,
baseField,
@ -1012,6 +1090,7 @@ const TEMPLATE_BUILDER_MAP: {
[key in FieldType]?: (arg: BuildInputFieldArg) => InputFieldTemplate;
} = {
BoardField: buildBoardInputFieldTemplate,
Any: buildAnyInputFieldTemplate,
boolean: buildBooleanInputFieldTemplate,
BooleanCollection: buildBooleanCollectionInputFieldTemplate,
BooleanPolymorphic: buildBooleanPolymorphicInputFieldTemplate,
@ -1047,6 +1126,11 @@ const TEMPLATE_BUILDER_MAP: {
LatentsField: buildLatentsInputFieldTemplate,
LatentsPolymorphic: buildLatentsPolymorphicInputFieldTemplate,
LoRAModelField: buildLoRAModelInputFieldTemplate,
MetadataItemField: buildMetadataItemInputFieldTemplate,
MetadataItemCollection: buildMetadataItemCollectionInputFieldTemplate,
MetadataItemPolymorphic: buildMetadataItemPolymorphicInputFieldTemplate,
MetadataField: buildMetadataDictInputFieldTemplate,
MetadataCollection: buildMetadataCollectionInputFieldTemplate,
MainModelField: buildMainModelInputFieldTemplate,
Scheduler: buildSchedulerInputFieldTemplate,
SDXLMainModelField: buildSDXLMainModelInputFieldTemplate,

View File

@ -3,6 +3,7 @@ import { FieldType, InputFieldTemplate, InputFieldValue } from '../types/types';
const FIELD_VALUE_FALLBACK_MAP: {
[key in FieldType]: InputFieldValue['value'];
} = {
Any: undefined,
enum: '',
BoardField: undefined,
boolean: false,
@ -38,6 +39,11 @@ const FIELD_VALUE_FALLBACK_MAP: {
LatentsCollection: [],
LatentsField: undefined,
LatentsPolymorphic: undefined,
MetadataItemField: undefined,
MetadataItemCollection: [],
MetadataItemPolymorphic: undefined,
MetadataField: undefined,
MetadataCollection: [],
LoRAModelField: undefined,
MainModelField: undefined,
ONNXModelField: undefined,

View File

@ -5,14 +5,14 @@ import {
CollectInvocation,
ControlField,
ControlNetInvocation,
MetadataAccumulatorInvocation,
CoreMetadataInvocation,
} from 'services/api/types';
import { NonNullableGraph } from '../../types/types';
import {
CANVAS_COHERENCE_DENOISE_LATENTS,
CONTROL_NET_COLLECT,
METADATA_ACCUMULATOR,
} from './constants';
import { upsertMetadata } from './metadata';
export const addControlNetToLinearGraph = (
state: RootState,
@ -23,9 +23,11 @@ export const addControlNetToLinearGraph = (
(ca) => ca.model?.base_model === state.generation.model?.base_model
);
const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as
| MetadataAccumulatorInvocation
| undefined;
// const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as
// | MetadataAccumulatorInvocation
// | undefined;
const controlNetMetadata: CoreMetadataInvocation['controlnets'] = [];
if (validControlNets.length) {
// Even though denoise_latents' control input is polymorphic, keep it simple and always use a collect
@ -99,15 +101,9 @@ export const addControlNetToLinearGraph = (
graph.nodes[controlNetNode.id] = controlNetNode as ControlNetInvocation;
if (metadataAccumulator?.controlnets) {
// metadata accumulator only needs a control field - not the whole node
// extract what we need and add to the accumulator
const controlField = omit(controlNetNode, [
'id',
'type',
]) as ControlField;
metadataAccumulator.controlnets.push(controlField);
}
controlNetMetadata.push(
omit(controlNetNode, ['id', 'type', 'is_intermediate']) as ControlField
);
graph.edges.push({
source: { node_id: controlNetNode.id, field: 'control' },
@ -117,5 +113,6 @@ export const addControlNetToLinearGraph = (
},
});
});
upsertMetadata(graph, { controlnets: controlNetMetadata });
}
};

View File

@ -1,25 +1,25 @@
import { logger } from 'app/logging/logger';
import { RootState } from 'app/store/store';
import { NonNullableGraph } from 'features/nodes/types/types';
import {
DenoiseLatentsInvocation,
ResizeLatentsInvocation,
NoiseInvocation,
LatentsToImageInvocation,
Edge,
LatentsToImageInvocation,
NoiseInvocation,
ResizeLatentsInvocation,
} from 'services/api/types';
import {
LATENTS_TO_IMAGE,
DENOISE_LATENTS,
NOISE,
MAIN_MODEL_LOADER,
METADATA_ACCUMULATOR,
LATENTS_TO_IMAGE_HRF,
DENOISE_LATENTS_HRF,
RESCALE_LATENTS,
LATENTS_TO_IMAGE,
LATENTS_TO_IMAGE_HRF,
MAIN_MODEL_LOADER,
NOISE,
NOISE_HRF,
RESCALE_LATENTS,
VAE_LOADER,
} from './constants';
import { logger } from 'app/logging/logger';
import { upsertMetadata } from './metadata';
// Copy certain connections from previous DENOISE_LATENTS to new DENOISE_LATENTS_HRF.
function copyConnectionsToDenoiseLatentsHrf(graph: NonNullableGraph): void {
@ -71,10 +71,8 @@ export const addHrfToGraph = (
}
const log = logger('txt2img');
const { vae } = state.generation;
const { vae, hrfWidth, hrfHeight, hrfStrength } = state.generation;
const isAutoVae = !vae;
const hrfWidth = state.generation.hrfWidth;
const hrfHeight = state.generation.hrfHeight;
// Pre-existing (original) graph nodes.
const originalDenoiseLatentsNode = graph.nodes[DENOISE_LATENTS] as
@ -116,7 +114,7 @@ export const addHrfToGraph = (
cfg_scale: originalDenoiseLatentsNode?.cfg_scale,
scheduler: originalDenoiseLatentsNode?.scheduler,
steps: originalDenoiseLatentsNode?.steps,
denoising_start: 1 - state.generation.hrfStrength,
denoising_start: 1 - hrfStrength,
denoising_end: 1,
};
@ -221,16 +219,6 @@ export const addHrfToGraph = (
field: 'latents',
},
},
{
source: {
node_id: METADATA_ACCUMULATOR,
field: 'metadata',
},
destination: {
node_id: LATENTS_TO_IMAGE_HRF,
field: 'metadata',
},
},
{
source: {
node_id: isAutoVae ? MAIN_MODEL_LOADER : VAE_LOADER,
@ -243,5 +231,11 @@ export const addHrfToGraph = (
}
);
upsertMetadata(graph, {
hrf_height: hrfHeight,
hrf_width: hrfWidth,
hrf_strength: hrfStrength,
});
copyConnectionsToDenoiseLatentsHrf(graph);
};

View File

@ -1,16 +1,18 @@
import { RootState } from 'app/store/store';
import { selectValidIPAdapters } from 'features/controlAdapters/store/controlAdaptersSlice';
import { omit } from 'lodash-es';
import {
CollectInvocation,
CoreMetadataInvocation,
IPAdapterInvocation,
MetadataAccumulatorInvocation,
IPAdapterMetadataField,
} from 'services/api/types';
import { NonNullableGraph } from '../../types/types';
import {
CANVAS_COHERENCE_DENOISE_LATENTS,
IP_ADAPTER_COLLECT,
METADATA_ACCUMULATOR,
} from './constants';
import { upsertMetadata } from './metadata';
export const addIPAdapterToLinearGraph = (
state: RootState,
@ -21,10 +23,6 @@ export const addIPAdapterToLinearGraph = (
(ca) => ca.model?.base_model === state.generation.model?.base_model
);
const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as
| MetadataAccumulatorInvocation
| undefined;
if (validIPAdapters.length) {
// Even though denoise_latents' control input is polymorphic, keep it simple and always use a collect
const ipAdapterCollectNode: CollectInvocation = {
@ -50,6 +48,7 @@ export const addIPAdapterToLinearGraph = (
},
});
}
const ipAdapterMetdata: CoreMetadataInvocation['ipAdapters'] = [];
validIPAdapters.forEach((ipAdapter) => {
if (!ipAdapter.model) {
@ -76,19 +75,13 @@ export const addIPAdapterToLinearGraph = (
graph.nodes[ipAdapterNode.id] = ipAdapterNode as IPAdapterInvocation;
if (metadataAccumulator?.ipAdapters) {
const ipAdapterField = {
image: {
image_name: ipAdapter.controlImage,
},
weight,
ip_adapter_model: model,
begin_step_percent: beginStepPct,
end_step_percent: endStepPct,
};
metadataAccumulator.ipAdapters.push(ipAdapterField);
}
ipAdapterMetdata.push(
omit(ipAdapterNode, [
'id',
'type',
'is_intermediate',
]) as IPAdapterMetadataField
);
graph.edges.push({
source: { node_id: ipAdapterNode.id, field: 'ip_adapter' },
@ -98,5 +91,7 @@ export const addIPAdapterToLinearGraph = (
},
});
});
upsertMetadata(graph, { ipAdapters: ipAdapterMetdata });
}
};

View File

@ -2,20 +2,20 @@ import { RootState } from 'app/store/store';
import { NonNullableGraph } from 'features/nodes/types/types';
import { forEach, size } from 'lodash-es';
import {
CoreMetadataInvocation,
LoraLoaderInvocation,
MetadataAccumulatorInvocation,
} from 'services/api/types';
import {
CANVAS_COHERENCE_DENOISE_LATENTS,
CANVAS_INPAINT_GRAPH,
CANVAS_OUTPAINT_GRAPH,
CANVAS_COHERENCE_DENOISE_LATENTS,
CLIP_SKIP,
LORA_LOADER,
MAIN_MODEL_LOADER,
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
POSITIVE_CONDITIONING,
} from './constants';
import { upsertMetadata } from './metadata';
export const addLoRAsToGraph = (
state: RootState,
@ -33,29 +33,29 @@ export const addLoRAsToGraph = (
const { loras } = state.lora;
const loraCount = size(loras);
const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as
| MetadataAccumulatorInvocation
| undefined;
if (loraCount > 0) {
// Remove modelLoaderNodeId unet connection to feed it to LoRAs
graph.edges = graph.edges.filter(
(e) =>
!(
e.source.node_id === modelLoaderNodeId &&
['unet'].includes(e.source.field)
)
);
// Remove CLIP_SKIP connections to conditionings to feed it through LoRAs
graph.edges = graph.edges.filter(
(e) =>
!(e.source.node_id === CLIP_SKIP && ['clip'].includes(e.source.field))
);
if (loraCount === 0) {
return;
}
// Remove modelLoaderNodeId unet connection to feed it to LoRAs
graph.edges = graph.edges.filter(
(e) =>
!(
e.source.node_id === modelLoaderNodeId &&
['unet'].includes(e.source.field)
)
);
// Remove CLIP_SKIP connections to conditionings to feed it through LoRAs
graph.edges = graph.edges.filter(
(e) =>
!(e.source.node_id === CLIP_SKIP && ['clip'].includes(e.source.field))
);
// we need to remember the last lora so we can chain from it
let lastLoraNodeId = '';
let currentLoraIndex = 0;
const loraMetadata: CoreMetadataInvocation['loras'] = [];
forEach(loras, (lora) => {
const { model_name, base_model, weight } = lora;
@ -69,13 +69,10 @@ export const addLoRAsToGraph = (
weight,
};
// add the lora to the metadata accumulator
if (metadataAccumulator?.loras) {
metadataAccumulator.loras.push({
lora: { model_name, base_model },
weight,
});
}
loraMetadata.push({
lora: { model_name, base_model },
weight,
});
// add to graph
graph.nodes[currentLoraNodeId] = loraLoaderNode;
@ -182,4 +179,6 @@ export const addLoRAsToGraph = (
lastLoraNodeId = currentLoraNodeId;
currentLoraIndex += 1;
});
upsertMetadata(graph, { loras: loraMetadata });
};

View File

@ -1,14 +1,14 @@
import { RootState } from 'app/store/store';
import { NonNullableGraph } from 'features/nodes/types/types';
import { forEach, size } from 'lodash-es';
import {
MetadataAccumulatorInvocation,
SDXLLoraLoaderInvocation,
} from 'services/api/types';
LoRAMetadataItem,
NonNullableGraph,
zLoRAMetadataItem,
} from 'features/nodes/types/types';
import { forEach, size } from 'lodash-es';
import { SDXLLoraLoaderInvocation } from 'services/api/types';
import {
CANVAS_COHERENCE_DENOISE_LATENTS,
LORA_LOADER,
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
POSITIVE_CONDITIONING,
SDXL_CANVAS_INPAINT_GRAPH,
@ -17,6 +17,7 @@ import {
SDXL_REFINER_INPAINT_CREATE_MASK,
SEAMLESS,
} from './constants';
import { upsertMetadata } from './metadata';
export const addSDXLLoRAsToGraph = (
state: RootState,
@ -34,9 +35,12 @@ export const addSDXLLoRAsToGraph = (
const { loras } = state.lora;
const loraCount = size(loras);
const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as
| MetadataAccumulatorInvocation
| undefined;
if (loraCount === 0) {
return;
}
const loraMetadata: LoRAMetadataItem[] = [];
// Handle Seamless Plugs
const unetLoaderId = modelLoaderNodeId;
@ -47,22 +51,17 @@ export const addSDXLLoRAsToGraph = (
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 === unetLoaderId && ['unet'].includes(e.source.field)
) &&
!(
e.source.node_id === clipLoaderId && ['clip'].includes(e.source.field)
) &&
!(
e.source.node_id === clipLoaderId &&
['clip2'].includes(e.source.field)
)
);
}
// Remove modelLoaderNodeId unet/clip/clip2 connections to feed it to LoRAs
graph.edges = graph.edges.filter(
(e) =>
!(
e.source.node_id === unetLoaderId && ['unet'].includes(e.source.field)
) &&
!(
e.source.node_id === clipLoaderId && ['clip'].includes(e.source.field)
) &&
!(e.source.node_id === clipLoaderId && ['clip2'].includes(e.source.field))
);
// we need to remember the last lora so we can chain from it
let lastLoraNodeId = '';
@ -80,16 +79,12 @@ export const addSDXLLoRAsToGraph = (
weight,
};
// add the lora to the metadata accumulator
if (metadataAccumulator) {
if (!metadataAccumulator.loras) {
metadataAccumulator.loras = [];
}
metadataAccumulator.loras.push({
loraMetadata.push(
zLoRAMetadataItem.parse({
lora: { model_name, base_model },
weight,
});
}
})
);
// add to graph
graph.nodes[currentLoraNodeId] = loraLoaderNode;
@ -242,4 +237,6 @@ export const addSDXLLoRAsToGraph = (
lastLoraNodeId = currentLoraNodeId;
currentLoraIndex += 1;
});
upsertMetadata(graph, { loras: loraMetadata });
};

View File

@ -2,7 +2,6 @@ import { RootState } from 'app/store/store';
import {
CreateDenoiseMaskInvocation,
ImageDTO,
MetadataAccumulatorInvocation,
SeamlessModeInvocation,
} from 'services/api/types';
import { NonNullableGraph } from '../../types/types';
@ -12,7 +11,6 @@ import {
LATENTS_TO_IMAGE,
MASK_COMBINE,
MASK_RESIZE_UP,
METADATA_ACCUMULATOR,
SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH,
SDXL_CANVAS_INPAINT_GRAPH,
SDXL_CANVAS_OUTPAINT_GRAPH,
@ -26,6 +24,7 @@ import {
SDXL_REFINER_SEAMLESS,
} from './constants';
import { buildSDXLStylePrompts } from './helpers/craftSDXLStylePrompt';
import { upsertMetadata } from './metadata';
export const addSDXLRefinerToGraph = (
state: RootState,
@ -58,21 +57,15 @@ export const addSDXLRefinerToGraph = (
return;
}
const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as
| MetadataAccumulatorInvocation
| undefined;
if (metadataAccumulator) {
metadataAccumulator.refiner_model = refinerModel;
metadataAccumulator.refiner_positive_aesthetic_score =
refinerPositiveAestheticScore;
metadataAccumulator.refiner_negative_aesthetic_score =
refinerNegativeAestheticScore;
metadataAccumulator.refiner_cfg_scale = refinerCFGScale;
metadataAccumulator.refiner_scheduler = refinerScheduler;
metadataAccumulator.refiner_start = refinerStart;
metadataAccumulator.refiner_steps = refinerSteps;
}
upsertMetadata(graph, {
refiner_model: refinerModel,
refiner_positive_aesthetic_score: refinerPositiveAestheticScore,
refiner_negative_aesthetic_score: refinerNegativeAestheticScore,
refiner_cfg_scale: refinerCFGScale,
refiner_scheduler: refinerScheduler,
refiner_start: refinerStart,
refiner_steps: refinerSteps,
});
const modelLoaderId = modelLoaderNodeId
? modelLoaderNodeId

View File

@ -1,19 +1,15 @@
import { RootState } from 'app/store/store';
import { NonNullableGraph } from 'features/nodes/types/types';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { SaveImageInvocation } from 'services/api/types';
import {
CANVAS_OUTPUT,
LATENTS_TO_IMAGE,
LATENTS_TO_IMAGE_HRF,
METADATA_ACCUMULATOR,
NSFW_CHECKER,
SAVE_IMAGE,
WATERMARKER,
} from './constants';
import {
MetadataAccumulatorInvocation,
SaveImageInvocation,
} from 'services/api/types';
import { RootState } from 'app/store/store';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
/**
* Set the `use_cache` field on the linear/canvas graph's final image output node to False.
@ -37,23 +33,6 @@ export const addSaveImageNode = (
graph.nodes[SAVE_IMAGE] = saveImageNode;
const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as
| MetadataAccumulatorInvocation
| undefined;
if (metadataAccumulator) {
graph.edges.push({
source: {
node_id: METADATA_ACCUMULATOR,
field: 'metadata',
},
destination: {
node_id: SAVE_IMAGE,
field: 'metadata',
},
});
}
const destination = {
node_id: SAVE_IMAGE,
field: 'image',

View File

@ -1,6 +1,7 @@
import { RootState } from 'app/store/store';
import { SeamlessModeInvocation } from 'services/api/types';
import { NonNullableGraph } from '../../types/types';
import { upsertMetadata } from './metadata';
import {
CANVAS_COHERENCE_DENOISE_LATENTS,
CANVAS_INPAINT_GRAPH,
@ -31,6 +32,17 @@ export const addSeamlessToLinearGraph = (
seamless_y: seamlessYAxis,
} as SeamlessModeInvocation;
if (seamlessXAxis) {
upsertMetadata(graph, {
seamless_x: seamlessXAxis,
});
}
if (seamlessYAxis) {
upsertMetadata(graph, {
seamless_y: seamlessYAxis,
});
}
let denoisingNodeId = DENOISE_LATENTS;
if (

View File

@ -3,15 +3,15 @@ import { selectValidT2IAdapters } from 'features/controlAdapters/store/controlAd
import { omit } from 'lodash-es';
import {
CollectInvocation,
MetadataAccumulatorInvocation,
CoreMetadataInvocation,
T2IAdapterInvocation,
} from 'services/api/types';
import { NonNullableGraph, T2IAdapterField } from '../../types/types';
import {
CANVAS_COHERENCE_DENOISE_LATENTS,
METADATA_ACCUMULATOR,
T2I_ADAPTER_COLLECT,
} from './constants';
import { upsertMetadata } from './metadata';
export const addT2IAdaptersToLinearGraph = (
state: RootState,
@ -22,10 +22,6 @@ export const addT2IAdaptersToLinearGraph = (
(ca) => ca.model?.base_model === state.generation.model?.base_model
);
const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as
| MetadataAccumulatorInvocation
| undefined;
if (validT2IAdapters.length) {
// Even though denoise_latents' control input is polymorphic, keep it simple and always use a collect
const t2iAdapterCollectNode: CollectInvocation = {
@ -51,6 +47,7 @@ export const addT2IAdaptersToLinearGraph = (
},
});
}
const t2iAdapterMetdata: CoreMetadataInvocation['t2iAdapters'] = [];
validT2IAdapters.forEach((t2iAdapter) => {
if (!t2iAdapter.model) {
@ -96,15 +93,13 @@ export const addT2IAdaptersToLinearGraph = (
graph.nodes[t2iAdapterNode.id] = t2iAdapterNode as T2IAdapterInvocation;
if (metadataAccumulator?.t2iAdapters) {
// metadata accumulator only needs a control field - not the whole node
// extract what we need and add to the accumulator
const t2iAdapterField = omit(t2iAdapterNode, [
t2iAdapterMetdata.push(
omit(t2iAdapterNode, [
'id',
'type',
]) as T2IAdapterField;
metadataAccumulator.t2iAdapters.push(t2iAdapterField);
}
'is_intermediate',
]) as T2IAdapterField
);
graph.edges.push({
source: { node_id: t2iAdapterNode.id, field: 't2i_adapter' },
@ -114,5 +109,7 @@ export const addT2IAdaptersToLinearGraph = (
},
});
});
upsertMetadata(graph, { t2iAdapters: t2iAdapterMetdata });
}
};

View File

@ -1,6 +1,5 @@
import { RootState } from 'app/store/store';
import { NonNullableGraph } from 'features/nodes/types/types';
import { MetadataAccumulatorInvocation } from 'services/api/types';
import {
CANVAS_COHERENCE_INPAINT_CREATE_MASK,
CANVAS_IMAGE_TO_IMAGE_GRAPH,
@ -14,7 +13,6 @@ import {
INPAINT_IMAGE,
LATENTS_TO_IMAGE,
MAIN_MODEL_LOADER,
METADATA_ACCUMULATOR,
ONNX_MODEL_LOADER,
SDXL_CANVAS_IMAGE_TO_IMAGE_GRAPH,
SDXL_CANVAS_INPAINT_GRAPH,
@ -26,6 +24,7 @@ import {
TEXT_TO_IMAGE_GRAPH,
VAE_LOADER,
} from './constants';
import { upsertMetadata } from './metadata';
export const addVAEToGraph = (
state: RootState,
@ -41,9 +40,6 @@ export const addVAEToGraph = (
);
const isAutoVae = !vae;
const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as
| MetadataAccumulatorInvocation
| undefined;
if (!isAutoVae) {
graph.nodes[VAE_LOADER] = {
@ -181,7 +177,7 @@ export const addVAEToGraph = (
}
}
if (vae && metadataAccumulator) {
metadataAccumulator.vae = vae;
if (vae) {
upsertMetadata(graph, { vae });
}
};

View File

@ -5,14 +5,8 @@ import {
ImageNSFWBlurInvocation,
ImageWatermarkInvocation,
LatentsToImageInvocation,
MetadataAccumulatorInvocation,
} from 'services/api/types';
import {
LATENTS_TO_IMAGE,
METADATA_ACCUMULATOR,
NSFW_CHECKER,
WATERMARKER,
} from './constants';
import { LATENTS_TO_IMAGE, NSFW_CHECKER, WATERMARKER } from './constants';
export const addWatermarkerToGraph = (
state: RootState,
@ -32,10 +26,6 @@ export const addWatermarkerToGraph = (
| ImageNSFWBlurInvocation
| undefined;
const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as
| MetadataAccumulatorInvocation
| undefined;
if (!nodeToAddTo) {
// something has gone terribly awry
return;
@ -80,17 +70,4 @@ export const addWatermarkerToGraph = (
},
});
}
if (metadataAccumulator) {
graph.edges.push({
source: {
node_id: METADATA_ACCUMULATOR,
field: 'metadata',
},
destination: {
node_id: WATERMARKER,
field: 'metadata',
},
});
}
};

View File

@ -1,12 +1,13 @@
import { BoardId } from 'features/gallery/store/types';
import { NonNullableGraph } from 'features/nodes/types/types';
import { ESRGANModelName } from 'features/parameters/store/postprocessingSlice';
import {
Graph,
ESRGANInvocation,
Graph,
SaveImageInvocation,
} from 'services/api/types';
import { REALESRGAN as ESRGAN, SAVE_IMAGE } from './constants';
import { BoardId } from 'features/gallery/store/types';
import { addCoreMetadataNode } from './metadata';
type Arg = {
image_name: string;
@ -55,5 +56,9 @@ export const buildAdHocUpscaleGraph = ({
],
};
addCoreMetadataNode(graph, {
esrgan_model: esrganModelName,
});
return graph;
};

View File

@ -20,12 +20,12 @@ import {
IMG2IMG_RESIZE,
LATENTS_TO_IMAGE,
MAIN_MODEL_LOADER,
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
NOISE,
POSITIVE_CONDITIONING,
SEAMLESS,
} from './constants';
import { addCoreMetadataNode } from './metadata';
/**
* Builds the Canvas tab's Image to Image graph.
@ -308,10 +308,7 @@ export const buildCanvasImageToImageGraph = (
});
}
// add metadata accumulator, which is only mostly populated - some fields are added later
graph.nodes[METADATA_ACCUMULATOR] = {
id: METADATA_ACCUMULATOR,
type: 'metadata_accumulator',
addCoreMetadataNode(graph, {
generation_mode: 'img2img',
cfg_scale,
width: !isUsingScaledDimensions ? width : scaledBoundingBoxDimensions.width,
@ -325,15 +322,10 @@ export const buildCanvasImageToImageGraph = (
steps,
rand_device: use_cpu ? 'cpu' : 'cuda',
scheduler,
vae: undefined, // option; set in addVAEToGraph
controlnets: [], // populated in addControlNetToLinearGraph
loras: [], // populated in addLoRAsToGraph
ipAdapters: [], // populated in addIPAdapterToLinearGraph
t2iAdapters: [],
clip_skip: clipSkip,
strength,
init_image: initialImage.image_name,
};
});
// Add Seamless To Graph
if (seamlessXAxis || seamlessYAxis) {

View File

@ -16,7 +16,6 @@ import {
IMAGE_TO_LATENTS,
IMG2IMG_RESIZE,
LATENTS_TO_IMAGE,
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
NOISE,
POSITIVE_CONDITIONING,
@ -28,6 +27,7 @@ import {
} from './constants';
import { buildSDXLStylePrompts } from './helpers/craftSDXLStylePrompt';
import { addT2IAdaptersToLinearGraph } from './addT2IAdapterToLinearGraph';
import { addCoreMetadataNode } from './metadata';
/**
* Builds the Canvas tab's Image to Image graph.
@ -319,10 +319,7 @@ export const buildCanvasSDXLImageToImageGraph = (
});
}
// add metadata accumulator, which is only mostly populated - some fields are added later
graph.nodes[METADATA_ACCUMULATOR] = {
id: METADATA_ACCUMULATOR,
type: 'metadata_accumulator',
addCoreMetadataNode(graph, {
generation_mode: 'img2img',
cfg_scale,
width: !isUsingScaledDimensions ? width : scaledBoundingBoxDimensions.width,
@ -336,24 +333,8 @@ export const buildCanvasSDXLImageToImageGraph = (
steps,
rand_device: use_cpu ? 'cpu' : 'cuda',
scheduler,
vae: undefined, // option; set in addVAEToGraph
controlnets: [], // populated in addControlNetToLinearGraph
loras: [], // populated in addLoRAsToGraph
ipAdapters: [], // populated in addIPAdapterToLinearGraph
t2iAdapters: [],
strength,
init_image: initialImage.image_name,
};
graph.edges.push({
source: {
node_id: METADATA_ACCUMULATOR,
field: 'metadata',
},
destination: {
node_id: CANVAS_OUTPUT,
field: 'metadata',
},
});
// Add Seamless To Graph

View File

@ -18,7 +18,6 @@ import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
CANVAS_OUTPUT,
LATENTS_TO_IMAGE,
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
NOISE,
ONNX_MODEL_LOADER,
@ -30,6 +29,7 @@ import {
SEAMLESS,
} from './constants';
import { buildSDXLStylePrompts } from './helpers/craftSDXLStylePrompt';
import { addCoreMetadataNode } from './metadata';
/**
* Builds the Canvas tab's Text to Image graph.
@ -301,10 +301,7 @@ export const buildCanvasSDXLTextToImageGraph = (
});
}
// add metadata accumulator, which is only mostly populated - some fields are added later
graph.nodes[METADATA_ACCUMULATOR] = {
id: METADATA_ACCUMULATOR,
type: 'metadata_accumulator',
addCoreMetadataNode(graph, {
generation_mode: 'txt2img',
cfg_scale,
width: !isUsingScaledDimensions ? width : scaledBoundingBoxDimensions.width,
@ -318,22 +315,6 @@ export const buildCanvasSDXLTextToImageGraph = (
steps,
rand_device: use_cpu ? 'cpu' : 'cuda',
scheduler,
vae: undefined, // option; set in addVAEToGraph
controlnets: [], // populated in addControlNetToLinearGraph
loras: [], // populated in addLoRAsToGraph
ipAdapters: [], // populated in addIPAdapterToLinearGraph
t2iAdapters: [],
};
graph.edges.push({
source: {
node_id: METADATA_ACCUMULATOR,
field: 'metadata',
},
destination: {
node_id: CANVAS_OUTPUT,
field: 'metadata',
},
});
// Add Seamless To Graph

View File

@ -21,13 +21,13 @@ import {
DENOISE_LATENTS,
LATENTS_TO_IMAGE,
MAIN_MODEL_LOADER,
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
NOISE,
ONNX_MODEL_LOADER,
POSITIVE_CONDITIONING,
SEAMLESS,
} from './constants';
import { addCoreMetadataNode } from './metadata';
/**
* Builds the Canvas tab's Text to Image graph.
@ -289,10 +289,7 @@ export const buildCanvasTextToImageGraph = (
});
}
// add metadata accumulator, which is only mostly populated - some fields are added later
graph.nodes[METADATA_ACCUMULATOR] = {
id: METADATA_ACCUMULATOR,
type: 'metadata_accumulator',
addCoreMetadataNode(graph, {
generation_mode: 'txt2img',
cfg_scale,
width: !isUsingScaledDimensions ? width : scaledBoundingBoxDimensions.width,
@ -306,23 +303,7 @@ export const buildCanvasTextToImageGraph = (
steps,
rand_device: use_cpu ? 'cpu' : 'cuda',
scheduler,
vae: undefined, // option; set in addVAEToGraph
controlnets: [], // populated in addControlNetToLinearGraph
loras: [], // populated in addLoRAsToGraph
ipAdapters: [], // populated in addIPAdapterToLinearGraph
t2iAdapters: [],
clip_skip: clipSkip,
};
graph.edges.push({
source: {
node_id: METADATA_ACCUMULATOR,
field: 'metadata',
},
destination: {
node_id: CANVAS_OUTPUT,
field: 'metadata',
},
});
// Add Seamless To Graph

View File

@ -7,10 +7,12 @@ import { components } from 'services/api/schema';
import { Batch, BatchConfig } from 'services/api/types';
import {
CANVAS_COHERENCE_NOISE,
METADATA,
METADATA_ACCUMULATOR,
NOISE,
POSITIVE_CONDITIONING,
} from './constants';
import { removeMetadata } from './metadata';
export const prepareLinearUIBatch = (
state: RootState,
@ -24,7 +26,6 @@ export const prepareLinearUIBatch = (
const data: Batch['data'] = [];
if (prompts.length === 1) {
unset(graph.nodes[METADATA_ACCUMULATOR], 'seed');
const seeds = generateSeeds({
count: iterations,
start: shouldRandomizeSeed ? undefined : seed,
@ -40,13 +41,13 @@ export const prepareLinearUIBatch = (
});
}
if (graph.nodes[METADATA_ACCUMULATOR]) {
zipped.push({
node_path: METADATA_ACCUMULATOR,
field_name: 'seed',
items: seeds,
});
}
// add to metadata
removeMetadata(graph, 'seed');
zipped.push({
node_path: METADATA,
field_name: 'seed',
items: seeds,
});
if (graph.nodes[CANVAS_COHERENCE_NOISE]) {
zipped.push({
@ -77,13 +78,13 @@ export const prepareLinearUIBatch = (
});
}
if (graph.nodes[METADATA_ACCUMULATOR]) {
firstBatchDatumList.push({
node_path: METADATA_ACCUMULATOR,
field_name: 'seed',
items: seeds,
});
}
// add to metadata
removeMetadata(graph, 'seed');
firstBatchDatumList.push({
node_path: METADATA,
field_name: 'seed',
items: seeds,
});
if (graph.nodes[CANVAS_COHERENCE_NOISE]) {
firstBatchDatumList.push({
@ -106,13 +107,15 @@ export const prepareLinearUIBatch = (
items: seeds,
});
}
if (graph.nodes[METADATA_ACCUMULATOR]) {
secondBatchDatumList.push({
node_path: METADATA_ACCUMULATOR,
field_name: 'seed',
items: seeds,
});
}
// add to metadata
removeMetadata(graph, 'seed');
secondBatchDatumList.push({
node_path: METADATA,
field_name: 'seed',
items: seeds,
});
if (graph.nodes[CANVAS_COHERENCE_NOISE]) {
secondBatchDatumList.push({
node_path: CANVAS_COHERENCE_NOISE,
@ -137,13 +140,13 @@ export const prepareLinearUIBatch = (
});
}
if (graph.nodes[METADATA_ACCUMULATOR]) {
firstBatchDatumList.push({
node_path: METADATA_ACCUMULATOR,
field_name: 'positive_prompt',
items: extendedPrompts,
});
}
// add to metadata
removeMetadata(graph, 'positive_prompt');
firstBatchDatumList.push({
node_path: METADATA,
field_name: 'positive_prompt',
items: extendedPrompts,
});
if (shouldConcatSDXLStylePrompt && model?.base_model === 'sdxl') {
unset(graph.nodes[METADATA_ACCUMULATOR], 'positive_style_prompt');
@ -160,13 +163,13 @@ export const prepareLinearUIBatch = (
});
}
if (graph.nodes[METADATA_ACCUMULATOR]) {
firstBatchDatumList.push({
node_path: METADATA_ACCUMULATOR,
field_name: 'positive_style_prompt',
items: stylePrompts,
});
}
// add to metadata
removeMetadata(graph, 'positive_style_prompt');
firstBatchDatumList.push({
node_path: METADATA,
field_name: 'positive_style_prompt',
items: extendedPrompts,
});
}
data.push(firstBatchDatumList);

View File

@ -21,13 +21,13 @@ import {
IMAGE_TO_LATENTS,
LATENTS_TO_IMAGE,
MAIN_MODEL_LOADER,
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
NOISE,
POSITIVE_CONDITIONING,
RESIZE,
SEAMLESS,
} from './constants';
import { addCoreMetadataNode } from './metadata';
/**
* Builds the Image to Image tab graph.
@ -311,10 +311,7 @@ export const buildLinearImageToImageGraph = (
});
}
// add metadata accumulator, which is only mostly populated - some fields are added later
graph.nodes[METADATA_ACCUMULATOR] = {
id: METADATA_ACCUMULATOR,
type: 'metadata_accumulator',
addCoreMetadataNode(graph, {
generation_mode: 'img2img',
cfg_scale,
height,
@ -326,25 +323,9 @@ export const buildLinearImageToImageGraph = (
steps,
rand_device: use_cpu ? 'cpu' : 'cuda',
scheduler,
vae: undefined, // option; set in addVAEToGraph
controlnets: [], // populated in addControlNetToLinearGraph
loras: [], // populated in addLoRAsToGraph
ipAdapters: [], // populated in addIPAdapterToLinearGraph
t2iAdapters: [], // populated in addT2IAdapterToLinearGraph
clip_skip: clipSkip,
strength,
init_image: initialImage.imageName,
};
graph.edges.push({
source: {
node_id: METADATA_ACCUMULATOR,
field: 'metadata',
},
destination: {
node_id: LATENTS_TO_IMAGE,
field: 'metadata',
},
});
// Add Seamless To Graph

View File

@ -18,7 +18,6 @@ import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import {
IMAGE_TO_LATENTS,
LATENTS_TO_IMAGE,
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
NOISE,
POSITIVE_CONDITIONING,
@ -30,6 +29,7 @@ import {
SEAMLESS,
} from './constants';
import { buildSDXLStylePrompts } from './helpers/craftSDXLStylePrompt';
import { addCoreMetadataNode } from './metadata';
/**
* Builds the Image to Image tab graph.
@ -331,10 +331,7 @@ export const buildLinearSDXLImageToImageGraph = (
});
}
// add metadata accumulator, which is only mostly populated - some fields are added later
graph.nodes[METADATA_ACCUMULATOR] = {
id: METADATA_ACCUMULATOR,
type: 'metadata_accumulator',
addCoreMetadataNode(graph, {
generation_mode: 'sdxl_img2img',
cfg_scale,
height,
@ -346,26 +343,10 @@ export const buildLinearSDXLImageToImageGraph = (
steps,
rand_device: use_cpu ? 'cpu' : 'cuda',
scheduler,
vae: undefined,
controlnets: [],
loras: [],
ipAdapters: [],
t2iAdapters: [],
strength: strength,
strength,
init_image: initialImage.imageName,
positive_style_prompt: positiveStylePrompt,
negative_style_prompt: negativeStylePrompt,
};
graph.edges.push({
source: {
node_id: METADATA_ACCUMULATOR,
field: 'metadata',
},
destination: {
node_id: LATENTS_TO_IMAGE,
field: 'metadata',
},
});
// Add Seamless To Graph

View File

@ -11,9 +11,9 @@ import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
import { addT2IAdaptersToLinearGraph } from './addT2IAdapterToLinearGraph';
import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import { addCoreMetadataNode } from './metadata';
import {
LATENTS_TO_IMAGE,
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
NOISE,
POSITIVE_CONDITIONING,
@ -225,10 +225,7 @@ export const buildLinearSDXLTextToImageGraph = (
],
};
// add metadata accumulator, which is only mostly populated - some fields are added later
graph.nodes[METADATA_ACCUMULATOR] = {
id: METADATA_ACCUMULATOR,
type: 'metadata_accumulator',
addCoreMetadataNode(graph, {
generation_mode: 'sdxl_txt2img',
cfg_scale,
height,
@ -240,24 +237,8 @@ export const buildLinearSDXLTextToImageGraph = (
steps,
rand_device: use_cpu ? 'cpu' : 'cuda',
scheduler,
vae: undefined,
controlnets: [],
loras: [],
ipAdapters: [],
t2iAdapters: [],
positive_style_prompt: positiveStylePrompt,
negative_style_prompt: negativeStylePrompt,
};
graph.edges.push({
source: {
node_id: METADATA_ACCUMULATOR,
field: 'metadata',
},
destination: {
node_id: LATENTS_TO_IMAGE,
field: 'metadata',
},
});
// Add Seamless To Graph

View File

@ -15,12 +15,12 @@ import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
import { addT2IAdaptersToLinearGraph } from './addT2IAdapterToLinearGraph';
import { addVAEToGraph } from './addVAEToGraph';
import { addWatermarkerToGraph } from './addWatermarkerToGraph';
import { addCoreMetadataNode } from './metadata';
import {
CLIP_SKIP,
DENOISE_LATENTS,
LATENTS_TO_IMAGE,
MAIN_MODEL_LOADER,
METADATA_ACCUMULATOR,
NEGATIVE_CONDITIONING,
NOISE,
ONNX_MODEL_LOADER,
@ -48,10 +48,6 @@ export const buildLinearTextToImageGraph = (
seamlessXAxis,
seamlessYAxis,
seed,
hrfWidth,
hrfHeight,
hrfStrength,
hrfEnabled: hrfEnabled,
} = state.generation;
const use_cpu = shouldUseCpuNoise;
@ -238,10 +234,7 @@ export const buildLinearTextToImageGraph = (
],
};
// add metadata accumulator, which is only mostly populated - some fields are added later
graph.nodes[METADATA_ACCUMULATOR] = {
id: METADATA_ACCUMULATOR,
type: 'metadata_accumulator',
addCoreMetadataNode(graph, {
generation_mode: 'txt2img',
cfg_scale,
height,
@ -253,26 +246,7 @@ export const buildLinearTextToImageGraph = (
steps,
rand_device: use_cpu ? 'cpu' : 'cuda',
scheduler,
vae: undefined, // option; set in addVAEToGraph
controlnets: [], // populated in addControlNetToLinearGraph
loras: [], // populated in addLoRAsToGraph
ipAdapters: [], // populated in addIPAdapterToLinearGraph
t2iAdapters: [], // populated in addT2IAdapterToLinearGraph
clip_skip: clipSkip,
hrf_width: hrfEnabled ? hrfWidth : undefined,
hrf_height: hrfEnabled ? hrfHeight : undefined,
hrf_strength: hrfEnabled ? hrfStrength : undefined,
};
graph.edges.push({
source: {
node_id: METADATA_ACCUMULATOR,
field: 'metadata',
},
destination: {
node_id: LATENTS_TO_IMAGE,
field: 'metadata',
},
});
// Add Seamless To Graph

View File

@ -35,7 +35,7 @@ export const buildNodesGraph = (nodesState: NodesState): Graph => {
const { nodes, edges } = nodesState;
const filteredNodes = nodes.filter(isInvocationNode);
const workflowJSON = JSON.stringify(buildWorkflow(nodesState));
// const workflowJSON = JSON.stringify(buildWorkflow(nodesState));
// Reduce the node editor nodes into invocation graph nodes
const parsedNodes = filteredNodes.reduce<NonNullable<Graph['nodes']>>(
@ -68,7 +68,8 @@ export const buildNodesGraph = (nodesState: NodesState): Graph => {
if (embedWorkflow) {
// add the workflow to the node
Object.assign(graphNode, { workflow: workflowJSON });
// Object.assign(graphNode, { workflow: workflowJSON });
Object.assign(graphNode, { workflow: buildWorkflow(nodesState) });
}
// Add it to the nodes object

View File

@ -56,7 +56,15 @@ export const IP_ADAPTER = 'ip_adapter';
export const DYNAMIC_PROMPT = 'dynamic_prompt';
export const IMAGE_COLLECTION = 'image_collection';
export const IMAGE_COLLECTION_ITERATE = 'image_collection_iterate';
export const METADATA = 'core_metadata';
export const BATCH_METADATA = 'batch_metadata';
export const BATCH_METADATA_COLLECT = 'batch_metadata_collect';
export const BATCH_SEED = 'batch_seed';
export const BATCH_PROMPT = 'batch_prompt';
export const BATCH_STYLE_PROMPT = 'batch_style_prompt';
export const METADATA_COLLECT = 'metadata_collect';
export const METADATA_ACCUMULATOR = 'metadata_accumulator';
export const MERGE_METADATA = 'merge_metadata';
export const REALESRGAN = 'esrgan';
export const DIVIDE = 'divide';
export const SCALE = 'scale_image';

View File

@ -0,0 +1,58 @@
import { NonNullableGraph } from 'features/nodes/types/types';
import { CoreMetadataInvocation } from 'services/api/types';
import { JsonObject } from 'type-fest';
import { METADATA, SAVE_IMAGE } from './constants';
export const addCoreMetadataNode = (
graph: NonNullableGraph,
metadata: Partial<CoreMetadataInvocation> | JsonObject
): void => {
graph.nodes[METADATA] = {
id: METADATA,
type: 'core_metadata',
...metadata,
};
graph.edges.push({
source: {
node_id: METADATA,
field: 'metadata',
},
destination: {
node_id: SAVE_IMAGE,
field: 'metadata',
},
});
return;
};
export const upsertMetadata = (
graph: NonNullableGraph,
metadata: Partial<CoreMetadataInvocation> | JsonObject
): void => {
const metadataNode = graph.nodes[METADATA] as
| CoreMetadataInvocation
| undefined;
if (!metadataNode) {
return;
}
Object.assign(metadataNode, metadata);
};
export const removeMetadata = (
graph: NonNullableGraph,
key: keyof CoreMetadataInvocation
): void => {
const metadataNode = graph.nodes[METADATA] as
| CoreMetadataInvocation
| undefined;
if (!metadataNode) {
return;
}
delete metadataNode[key];
};

View File

@ -4,7 +4,6 @@ import { reduce, startCase } from 'lodash-es';
import { OpenAPIV3_1 } from 'openapi-types';
import { AnyInvocationType } from 'services/events/types';
import {
FieldType,
InputFieldTemplate,
InvocationSchemaObject,
InvocationTemplate,
@ -16,18 +15,11 @@ import {
} from '../types/types';
import { buildInputFieldTemplate, getFieldType } from './fieldTemplateBuilders';
const RESERVED_INPUT_FIELD_NAMES = ['id', 'type', 'metadata', 'use_cache'];
const RESERVED_INPUT_FIELD_NAMES = ['id', 'type', 'use_cache'];
const RESERVED_OUTPUT_FIELD_NAMES = ['type'];
const RESERVED_FIELD_TYPES = [
'WorkflowField',
'MetadataField',
'IsIntermediate',
];
const RESERVED_FIELD_TYPES = ['IsIntermediate'];
const invocationDenylist: AnyInvocationType[] = [
'graph',
'metadata_accumulator',
];
const invocationDenylist: AnyInvocationType[] = ['graph'];
const isReservedInputField = (nodeType: string, fieldName: string) => {
if (RESERVED_INPUT_FIELD_NAMES.includes(fieldName)) {
@ -42,7 +34,7 @@ const isReservedInputField = (nodeType: string, fieldName: string) => {
return false;
};
const isReservedFieldType = (fieldType: FieldType) => {
const isReservedFieldType = (fieldType: string) => {
if (RESERVED_FIELD_TYPES.includes(fieldType)) {
return true;
}
@ -86,6 +78,7 @@ export const parseSchema = (
const tags = schema.tags ?? [];
const description = schema.description ?? '';
const version = schema.version;
let withWorkflow = false;
const inputs = reduce(
schema.properties,
@ -112,7 +105,7 @@ export const parseSchema = (
const fieldType = property.ui_type ?? getFieldType(property);
if (!isFieldType(fieldType)) {
if (!fieldType) {
logger('nodes').warn(
{
node: type,
@ -120,11 +113,16 @@ export const parseSchema = (
fieldType,
field: parseify(property),
},
'Skipping unknown input field type'
'Missing input field type'
);
return inputsAccumulator;
}
if (fieldType === 'WorkflowField') {
withWorkflow = true;
return inputsAccumulator;
}
if (isReservedFieldType(fieldType)) {
logger('nodes').trace(
{
@ -133,7 +131,20 @@ export const parseSchema = (
fieldType,
field: parseify(property),
},
'Skipping reserved field type'
`Skipping reserved input field type: ${fieldType}`
);
return inputsAccumulator;
}
if (!isFieldType(fieldType)) {
logger('nodes').warn(
{
node: type,
fieldName: propertyName,
fieldType,
field: parseify(property),
},
`Skipping unknown input field type: ${fieldType}`
);
return inputsAccumulator;
}
@ -146,7 +157,7 @@ export const parseSchema = (
);
if (!field) {
logger('nodes').debug(
logger('nodes').warn(
{
node: type,
fieldName: propertyName,
@ -248,6 +259,7 @@ export const parseSchema = (
inputs,
outputs,
useCache,
withWorkflow,
};
Object.assign(invocationsAccumulator, { [type]: invocation });