fix(ui): rip out broken recall logic, NO TS ERRORS

This commit is contained in:
psychedelicious 2024-08-23 19:22:29 +10:00
parent 45bd85c039
commit 768e6a3c55
14 changed files with 109 additions and 852 deletions

View File

@ -1,16 +0,0 @@
/**
* This file contains IDs, names, and ID getters for konva layers and objects.
*/
// Getters for non-singleton layer and object IDs
export const getRGId = (entityId: string) => `region_${entityId}`;
export const getLayerId = (entityId: string) => `layer_${entityId}`;
export const getBrushLineId = (entityId: string, lineId: string, isBuffer?: boolean) =>
`${isBuffer ? 'buffer_' : ''}brush_line_${lineId}`;
export const getEraserLineId = (entityId: string, lineId: string, isBuffer?: boolean) =>
`${isBuffer ? 'buffer_' : ''}eraser_line_${lineId}`;
export const getRectShapeId = (entityId: string, rectId: string, isBuffer?: boolean) =>
`${isBuffer ? 'buffer_' : ''}rect_${rectId}`;
export const getImageObjectId = (entityId: string, imageId: string) => `image_${imageId}`;
export const getCAId = (entityId: string) => `control_adapter_${entityId}`;
export const getIPAId = (entityId: string) => `ip_adapter_${entityId}`;

View File

@ -463,11 +463,11 @@ export const {
bboxSizeOptimized,
// Raster layers
rasterLayerAdded,
rasterLayerRecalled,
// rasterLayerRecalled,
rasterLayerConvertedToControlLayer,
// Control layers
controlLayerAdded,
controlLayerRecalled,
// controlLayerRecalled,
controlLayerConvertedToRasterLayer,
controlLayerModelChanged,
controlLayerControlModeChanged,
@ -476,7 +476,7 @@ export const {
controlLayerWithTransparencyEffectToggled,
// IP Adapters
ipaAdded,
ipaRecalled,
// ipaRecalled,
ipaImageChanged,
ipaMethodChanged,
ipaModelChanged,
@ -485,7 +485,7 @@ export const {
ipaBeginEndStepPctChanged,
// Regions
rgAdded,
rgRecalled,
// rgRecalled,
rgPositivePromptChanged,
rgNegativePromptChanged,
rgFillColorChanged,
@ -545,7 +545,7 @@ export const {
loraAllDeleted,
// Inpaint mask
inpaintMaskAdded,
inpaintMaskRecalled,
// inpaintMaskRecalled,
inpaintMaskFillColorChanged,
inpaintMaskFillStyleChanged,
// Staging

View File

@ -1,10 +1,6 @@
import { useAppSelector } from 'app/store/storeHooks';
import { MetadataControlNets } from 'features/metadata/components/MetadataControlNets';
import { MetadataIPAdapters } from 'features/metadata/components/MetadataIPAdapters';
import { MetadataItem } from 'features/metadata/components/MetadataItem';
import { MetadataLayers } from 'features/metadata/components/MetadataLayers';
import { MetadataLoRAs } from 'features/metadata/components/MetadataLoRAs';
import { MetadataT2IAdapters } from 'features/metadata/components/MetadataT2IAdapters';
import { handlers } from 'features/metadata/util/handlers';
import { selectActiveTab } from 'features/ui/store/uiSelectors';
import { memo } from 'react';
@ -49,10 +45,6 @@ const ImageMetadataActions = (props: Props) => {
<MetadataItem metadata={metadata} handlers={handlers.refinerStart} />
<MetadataItem metadata={metadata} handlers={handlers.refinerSteps} />
<MetadataLoRAs metadata={metadata} />
{activeTabName === 'generation' && <MetadataLayers metadata={metadata} />}
{activeTabName !== 'generation' && <MetadataControlNets metadata={metadata} />}
{activeTabName !== 'generation' && <MetadataT2IAdapters metadata={metadata} />}
{activeTabName !== 'generation' && <MetadataIPAdapters metadata={metadata} />}
</>
);
};

View File

@ -1,72 +0,0 @@
import { MetadataItemView } from 'features/metadata/components/MetadataItemView';
import type { ControlNetConfigMetadata, MetadataHandlers } from 'features/metadata/types';
import { handlers } from 'features/metadata/util/handlers';
import { useCallback, useEffect, useMemo, useState } from 'react';
type Props = {
metadata: unknown;
};
export const MetadataControlNets = ({ metadata }: Props) => {
const [controlNets, setControlNets] = useState<ControlNetConfigMetadata[]>([]);
useEffect(() => {
const parse = async () => {
try {
const parsed = await handlers.controlNets.parse(metadata);
setControlNets(parsed);
} catch (e) {
setControlNets([]);
}
};
parse();
}, [metadata]);
const label = useMemo(() => handlers.controlNets.getLabel(), []);
return (
<>
{controlNets.map((controlNet, i) => (
<MetadataViewControlNet
key={`${controlNet.model.key}-${i}`}
label={label}
controlNet={controlNet}
handlers={handlers.controlNets}
/>
))}
</>
);
};
const MetadataViewControlNet = ({
label,
controlNet,
handlers,
}: {
label: string;
controlNet: ControlNetConfigMetadata;
handlers: MetadataHandlers<ControlNetConfigMetadata[], ControlNetConfigMetadata>;
}) => {
const onRecall = useCallback(() => {
if (!handlers.recallItem) {
return;
}
handlers.recallItem(controlNet, true);
}, [handlers, controlNet]);
const [renderedValue, setRenderedValue] = useState<React.ReactNode>(null);
useEffect(() => {
const _renderValue = async () => {
if (!handlers.renderItemValue) {
setRenderedValue(null);
return;
}
const rendered = await handlers.renderItemValue(controlNet);
setRenderedValue(rendered);
};
_renderValue();
}, [handlers, controlNet]);
return <MetadataItemView label={label} isDisabled={false} onRecall={onRecall} renderedValue={renderedValue} />;
};

View File

@ -1,72 +0,0 @@
import { MetadataItemView } from 'features/metadata/components/MetadataItemView';
import type { IPAdapterConfigMetadata, MetadataHandlers } from 'features/metadata/types';
import { handlers } from 'features/metadata/util/handlers';
import { useCallback, useEffect, useMemo, useState } from 'react';
type Props = {
metadata: unknown;
};
export const MetadataIPAdapters = ({ metadata }: Props) => {
const [ipAdapters, setIPAdapters] = useState<IPAdapterConfigMetadata[]>([]);
useEffect(() => {
const parse = async () => {
try {
const parsed = await handlers.ipAdapters.parse(metadata);
setIPAdapters(parsed);
} catch (e) {
setIPAdapters([]);
}
};
parse();
}, [metadata]);
const label = useMemo(() => handlers.ipAdapters.getLabel(), []);
return (
<>
{ipAdapters.map((ipAdapter, i) => (
<MetadataViewIPAdapter
key={`${ipAdapter.model.key}-${i}`}
label={label}
ipAdapter={ipAdapter}
handlers={handlers.ipAdapters}
/>
))}
</>
);
};
const MetadataViewIPAdapter = ({
label,
ipAdapter,
handlers,
}: {
label: string;
ipAdapter: IPAdapterConfigMetadata;
handlers: MetadataHandlers<IPAdapterConfigMetadata[], IPAdapterConfigMetadata>;
}) => {
const onRecall = useCallback(() => {
if (!handlers.recallItem) {
return;
}
handlers.recallItem(ipAdapter, true);
}, [handlers, ipAdapter]);
const [renderedValue, setRenderedValue] = useState<React.ReactNode>(null);
useEffect(() => {
const _renderValue = async () => {
if (!handlers.renderItemValue) {
setRenderedValue(null);
return;
}
const rendered = await handlers.renderItemValue(ipAdapter);
setRenderedValue(rendered);
};
_renderValue();
}, [handlers, ipAdapter]);
return <MetadataItemView label={label} isDisabled={false} onRecall={onRecall} renderedValue={renderedValue} />;
};

View File

@ -1,68 +0,0 @@
import type { CanvasRasterLayerState } from 'features/controlLayers/store/types';
import { MetadataItemView } from 'features/metadata/components/MetadataItemView';
import type { MetadataHandlers } from 'features/metadata/types';
import { handlers } from 'features/metadata/util/handlers';
import { useCallback, useEffect, useMemo, useState } from 'react';
type Props = {
metadata: unknown;
};
export const MetadataLayers = ({ metadata }: Props) => {
const [layers, setLayers] = useState<CanvasRasterLayerState[]>([]);
useEffect(() => {
const parse = async () => {
try {
const parsed = await handlers.layers.parse(metadata);
setLayers(parsed);
} catch (e) {
setLayers([]);
}
};
parse();
}, [metadata]);
const label = useMemo(() => handlers.layers.getLabel(), []);
return (
<>
{layers.map((layer) => (
<MetadataViewLayer key={layer.id} label={label} layer={layer} handlers={handlers.layers} />
))}
</>
);
};
const MetadataViewLayer = ({
label,
layer,
handlers,
}: {
label: string;
layer: CanvasRasterLayerState;
handlers: MetadataHandlers<CanvasRasterLayerState[], CanvasRasterLayerState>;
}) => {
const onRecall = useCallback(() => {
if (!handlers.recallItem) {
return;
}
handlers.recallItem(layer, true);
}, [handlers, layer]);
const [renderedValue, setRenderedValue] = useState<React.ReactNode>(null);
useEffect(() => {
const _renderValue = async () => {
if (!handlers.renderItemValue) {
setRenderedValue(null);
return;
}
const rendered = await handlers.renderItemValue(layer);
setRenderedValue(rendered);
};
_renderValue();
}, [handlers, layer]);
return <MetadataItemView label={label} isDisabled={false} onRecall={onRecall} renderedValue={renderedValue} />;
};

View File

@ -1,72 +0,0 @@
import { MetadataItemView } from 'features/metadata/components/MetadataItemView';
import type { MetadataHandlers, T2IAdapterConfigMetadata } from 'features/metadata/types';
import { handlers } from 'features/metadata/util/handlers';
import { useCallback, useEffect, useMemo, useState } from 'react';
type Props = {
metadata: unknown;
};
export const MetadataT2IAdapters = ({ metadata }: Props) => {
const [t2iAdapters, setT2IAdapters] = useState<T2IAdapterConfigMetadata[]>([]);
useEffect(() => {
const parse = async () => {
try {
const parsed = await handlers.t2iAdapters.parse(metadata);
setT2IAdapters(parsed);
} catch (e) {
setT2IAdapters([]);
}
};
parse();
}, [metadata]);
const label = useMemo(() => handlers.t2iAdapters.getLabel(), []);
return (
<>
{t2iAdapters.map((t2iAdapter, i) => (
<MetadataViewT2IAdapter
key={`${t2iAdapter.model.key}-${i}`}
label={label}
t2iAdapter={t2iAdapter}
handlers={handlers.t2iAdapters}
/>
))}
</>
);
};
const MetadataViewT2IAdapter = ({
label,
t2iAdapter,
handlers,
}: {
label: string;
t2iAdapter: T2IAdapterConfigMetadata;
handlers: MetadataHandlers<T2IAdapterConfigMetadata[], T2IAdapterConfigMetadata>;
}) => {
const onRecall = useCallback(() => {
if (!handlers.recallItem) {
return;
}
handlers.recallItem(t2iAdapter, true);
}, [handlers, t2iAdapter]);
const [renderedValue, setRenderedValue] = useState<React.ReactNode>(null);
useEffect(() => {
const _renderValue = async () => {
if (!handlers.renderItemValue) {
setRenderedValue(null);
return;
}
const rendered = await handlers.renderItemValue(t2iAdapter);
setRenderedValue(rendered);
};
_renderValue();
}, [handlers, t2iAdapter]);
return <MetadataItemView label={label} isDisabled={false} onRecall={onRecall} renderedValue={renderedValue} />;
};

View File

@ -148,7 +148,3 @@ export type BuildMetadataHandlers = <TValue, TItem>(
export type ControlNetConfigMetadata = O.NonNullable<ControlNetConfig, 'model'>;
export type T2IAdapterConfigMetadata = O.NonNullable<T2IAdapterConfig, 'model'>;
export type IPAdapterConfigMetadata = O.NonNullable<IPAdapterConfig, 'model'>;
export type AnyControlAdapterConfigMetadata =
| ControlNetConfigMetadata
| T2IAdapterConfigMetadata
| IPAdapterConfigMetadata;

View File

@ -2,9 +2,8 @@ import { getStore } from 'app/store/nanostores/store';
import { deepClone } from 'common/util/deepClone';
import { objectKeys } from 'common/util/objectKeys';
import { shouldConcatPromptsChanged } from 'features/controlLayers/store/canvasV2Slice';
import type { CanvasRasterLayerState, LoRA } from 'features/controlLayers/store/types';
import type { LoRA } from 'features/controlLayers/store/types';
import type {
AnyControlAdapterConfigMetadata,
BuildMetadataHandlers,
MetadataGetLabelFunc,
MetadataHandlers,
@ -19,7 +18,6 @@ import type { ModelIdentifierField } from 'features/nodes/types/common';
import { toast } from 'features/toast/toast';
import { t } from 'i18next';
import { size } from 'lodash-es';
import { assert } from 'tsafe';
import { parsers } from './parsers';
import { recallers } from './recallers';
@ -40,57 +38,6 @@ const renderLoRAValue: MetadataRenderValueFunc<LoRA> = async (value) => {
return `${value.model.key} (${value.model.base.toUpperCase()}) - ${value.weight}`;
}
};
const renderControlAdapterValue: MetadataRenderValueFunc<AnyControlAdapterConfigMetadata> = async (value) => {
try {
const modelConfig = await fetchModelConfig(value.model.key ?? 'none');
return `${modelConfig.name} (${modelConfig.base.toUpperCase()}) - ${value.weight}`;
} catch {
return `${value.model.key} (${value.model.base.toUpperCase()}) - ${value.weight}`;
}
};
const renderLayerValue: MetadataRenderValueFunc<CanvasRasterLayerState> = (layer) => {
if (layer.type === 'initial_image_layer') {
let rendered = t('controlLayers.globalInitialImageLayer');
if (layer.image) {
rendered += ` (${layer.image})`;
}
return rendered;
}
if (layer.type === 'control_adapter_layer') {
let rendered = t('controlLayers.globalControlAdapterLayer');
const model = layer.controlAdapter.model;
if (model) {
rendered += ` (${model.name} - ${model.base.toUpperCase()})`;
}
return rendered;
}
if (layer.type === 'ip_adapter_layer') {
let rendered = t('controlLayers.globalIPAdapterLayer');
const model = layer.ipAdapter.model;
if (model) {
rendered += ` (${model.name} - ${model.base.toUpperCase()})`;
}
return rendered;
}
if (layer.type === 'regional_guidance_layer') {
const rendered = t('controlLayers.regionalGuidanceLayer');
const items: string[] = [];
if (layer.positivePrompt) {
items.push(`Positive: ${layer.positivePrompt}`);
}
if (layer.negativePrompt) {
items.push(`Negative: ${layer.negativePrompt}`);
}
if (layer.ipAdapters.length > 0) {
items.push(`${layer.ipAdapters.length} IP Adapters`);
}
return `${rendered} (${items.join(', ')})`;
}
assert(false, 'Unknown layer type');
};
const renderLayersValue: MetadataRenderValueFunc<CanvasRasterLayerState[]> = (layers) => {
return `${layers.length} ${t('controlLayers.layers', { count: layers.length })}`;
};
const parameterSetToast = (parameter: string) => {
toast({
@ -328,26 +275,6 @@ export const handlers = {
}),
// Arrays of models
controlNets: buildHandlers({
getLabel: () => t('common.controlNet'),
parser: parsers.controlNets,
itemParser: parsers.controlNet,
recaller: recallers.controlNets,
itemRecaller: recallers.controlNet,
validator: validators.controlNets,
itemValidator: validators.controlNet,
renderItemValue: renderControlAdapterValue,
}),
ipAdapters: buildHandlers({
getLabel: () => t('common.ipAdapter'),
parser: parsers.ipAdapters,
itemParser: parsers.ipAdapter,
recaller: recallers.ipAdapters,
itemRecaller: recallers.ipAdapter,
validator: validators.ipAdapters,
itemValidator: validators.ipAdapter,
renderItemValue: renderControlAdapterValue,
}),
loras: buildHandlers({
getLabel: () => t('models.lora'),
parser: parsers.loras,
@ -358,28 +285,6 @@ export const handlers = {
itemValidator: validators.lora,
renderItemValue: renderLoRAValue,
}),
t2iAdapters: buildHandlers({
getLabel: () => t('common.t2iAdapter'),
parser: parsers.t2iAdapters,
itemParser: parsers.t2iAdapter,
recaller: recallers.t2iAdapters,
itemRecaller: recallers.t2iAdapter,
validator: validators.t2iAdapters,
itemValidator: validators.t2iAdapter,
renderItemValue: renderControlAdapterValue,
}),
layers: buildHandlers({
getLabel: () => t('controlLayers.layers_one'),
parser: parsers.layers,
itemParser: parsers.layer,
recaller: recallers.layers,
itemRecaller: recallers.layer,
validator: validators.layers,
itemValidator: validators.layer,
renderItemValue: renderLayerValue,
renderValue: renderLayersValue,
getIsVisible: (value) => value.length > 0,
}),
} as const;
type ParsedValue = Awaited<ReturnType<(typeof handlers)[keyof typeof handlers]['parse']>>;
@ -406,9 +311,9 @@ export const parseAndRecallImageDimensions = (metadata: unknown) => {
};
// These handlers should be omitted when recalling to control layers
const TO_CONTROL_LAYERS_SKIP_KEYS: (keyof typeof handlers)[] = ['controlNets', 'ipAdapters', 't2iAdapters', 'strength'];
const TO_CONTROL_LAYERS_SKIP_KEYS: (keyof typeof handlers)[] = ['strength'];
// These handlers should be omitted when recalling to the rest of the app
const NOT_TO_CONTROL_LAYERS_SKIP_KEYS: (keyof typeof handlers)[] = ['layers'];
const NOT_TO_CONTROL_LAYERS_SKIP_KEYS: (keyof typeof handlers)[] = [];
export const parseAndRecallAllMetadata = async (
metadata: unknown,

View File

@ -76,17 +76,17 @@ const fetchModelConfigByAttrs = async (name: string, base: BaseModelType, type:
* @returns A promise that resolves to the model config.
* @throws {ModelConfigNotFoundError} If the model config is unable to be fetched.
*/
export const fetchModelConfigByIdentifier = async (identifier: ModelIdentifierField): Promise<AnyModelConfig> => {
try {
return await fetchModelConfig(identifier.key);
} catch {
try {
return await fetchModelConfigByAttrs(identifier.name, identifier.base, identifier.type);
} catch {
throw new ModelConfigNotFoundError(`Unable to retrieve model config for identifier ${identifier}`);
}
}
};
// export const fetchModelConfigByIdentifier = async (identifier: ModelIdentifierField): Promise<AnyModelConfig> => {
// try {
// return await fetchModelConfig(identifier.key);
// } catch {
// try {
// return await fetchModelConfigByAttrs(identifier.name, identifier.base, identifier.type);
// } catch {
// throw new ModelConfigNotFoundError(`Unable to retrieve model config for identifier ${identifier}`);
// }
// }
// };
/**
* Fetches the model config for a given model key and type, and ensures that the model config is of a specific type.

View File

@ -1,18 +1,18 @@
import { getCAId, getImageObjectId, getIPAId, getLayerId } from 'features/controlLayers/konva/naming';
import { getPrefixedId } from 'features/controlLayers/konva/util';
import { defaultLoRAConfig } from 'features/controlLayers/store/lorasReducers';
import type {
CanvasControlAdapterState,
CanvasControlLayerState,
CanvasInpaintMaskState,
CanvasIPAdapterState,
CanvasRasterLayerState,
CanvasRegionalGuidanceState,
LoRA,
} from 'features/controlLayers/store/types';
import {
IMAGE_FILTERS,
imageDTOToImageWithDims,
initialControlNet,
initialIPAdapter,
initialT2IAdapter,
isFilterType,
zCanvasRasterLayerState,
} from 'features/controlLayers/store/types';
import type {
@ -76,8 +76,6 @@ import {
isT2IAdapterModelConfig,
isVAEModelConfig,
} from 'services/api/types';
import { assert } from 'tsafe';
import { v4 as uuidv4 } from 'uuid';
export const MetadataParsePendingToken = Symbol('pending');
export const MetadataParseFailedToken = Symbol('failed');
@ -222,6 +220,7 @@ const parseLoRA: MetadataParseFunc<LoRA> = async (metadataItem) => {
const loraModelConfig = await fetchModelConfigWithTypeGuard(key, isLoRAModelConfig);
return {
id: getPrefixedId('lora'),
model: zModelIdentifierField.parse(loraModelConfig),
weight: isParameterLoRAWeight(weight) ? weight : defaultLoRAConfig.weight,
isEnabled: true,
@ -245,14 +244,6 @@ const parseControlNet: MetadataParseFunc<ControlNetConfigMetadata> = async (meta
const control_model = await getProperty(metadataItem, 'control_model');
const key = await getModelKey(control_model, 'controlnet');
const controlNetModel = await fetchModelConfigWithTypeGuard(key, isControlNetModelConfig);
const image = zControlField.shape.image
.nullish()
.catch(null)
.parse(await getProperty(metadataItem, 'image'));
const processedImage = zControlField.shape.image
.nullish()
.catch(null)
.parse(await getProperty(metadataItem, 'processed_image'));
const control_weight = zControlField.shape.control_weight
.nullish()
.catch(null)
@ -269,28 +260,16 @@ const parseControlNet: MetadataParseFunc<ControlNetConfigMetadata> = async (meta
.nullish()
.catch(null)
.parse(await getProperty(metadataItem, 'control_mode'));
const resize_mode = zControlField.shape.resize_mode
.nullish()
.catch(null)
.parse(await getProperty(metadataItem, 'resize_mode'));
const { processorType, processorNode } = buildControlAdapterProcessor(controlNetModel);
const controlNet: ControlNetConfigMetadata = {
type: 'controlnet',
isEnabled: true,
model: zModelIdentifierField.parse(controlNetModel),
weight: typeof control_weight === 'number' ? control_weight : initialControlNet.weight,
beginStepPct: begin_step_percent ?? initialControlNet.beginStepPct,
endStepPct: end_step_percent ?? initialControlNet.endStepPct,
beginEndStepPct: [
begin_step_percent ?? initialControlNet.beginEndStepPct[0],
end_step_percent ?? initialControlNet.beginEndStepPct[1],
],
controlMode: control_mode ?? initialControlNet.controlMode,
resizeMode: resize_mode ?? initialControlNet.resizeMode,
controlImage: image?.image_name ?? null,
processedControlImage: processedImage?.image_name ?? null,
processorType,
processorNode,
shouldAutoConfig: true,
id: uuidv4(),
};
return controlNet;
@ -314,14 +293,6 @@ const parseT2IAdapter: MetadataParseFunc<T2IAdapterConfigMetadata> = async (meta
const key = await getModelKey(t2i_adapter_model, 't2i_adapter');
const t2iAdapterModel = await fetchModelConfigWithTypeGuard(key, isT2IAdapterModelConfig);
const image = zT2IAdapterField.shape.image
.nullish()
.catch(null)
.parse(await getProperty(metadataItem, 'image'));
const processedImage = zT2IAdapterField.shape.image
.nullish()
.catch(null)
.parse(await getProperty(metadataItem, 'processed_image'));
const weight = zT2IAdapterField.shape.weight
.nullish()
.catch(null)
@ -334,27 +305,15 @@ const parseT2IAdapter: MetadataParseFunc<T2IAdapterConfigMetadata> = async (meta
.nullish()
.catch(null)
.parse(await getProperty(metadataItem, 'end_step_percent'));
const resize_mode = zT2IAdapterField.shape.resize_mode
.nullish()
.catch(null)
.parse(await getProperty(metadataItem, 'resize_mode'));
const { processorType, processorNode } = buildControlAdapterProcessor(t2iAdapterModel);
const t2iAdapter: T2IAdapterConfigMetadata = {
type: 't2i_adapter',
isEnabled: true,
model: zModelIdentifierField.parse(t2iAdapterModel),
weight: typeof weight === 'number' ? weight : initialT2IAdapter.weight,
beginStepPct: begin_step_percent ?? initialT2IAdapter.beginStepPct,
endStepPct: end_step_percent ?? initialT2IAdapter.endStepPct,
resizeMode: resize_mode ?? initialT2IAdapter.resizeMode,
controlImage: image?.image_name ?? null,
processedControlImage: processedImage?.image_name ?? null,
processorType,
processorNode,
shouldAutoConfig: true,
id: uuidv4(),
beginEndStepPct: [
begin_step_percent ?? initialT2IAdapter.beginEndStepPct[0],
end_step_percent ?? initialT2IAdapter.beginEndStepPct[1],
],
};
return t2iAdapter;
@ -378,10 +337,10 @@ const parseIPAdapter: MetadataParseFunc<IPAdapterConfigMetadata> = async (metada
const key = await getModelKey(ip_adapter_model, 'ip_adapter');
const ipAdapterModel = await fetchModelConfigWithTypeGuard(key, isIPAdapterModelConfig);
const image = zIPAdapterField.shape.image
.nullish()
.catch(null)
.parse(await getProperty(metadataItem, 'image'));
// const image = zIPAdapterField.shape.image
// .nullish()
// .catch(null)
// .parse(await getProperty(metadataItem, 'image'));
const weight = zIPAdapterField.shape.weight
.nullish()
.catch(null)
@ -400,16 +359,15 @@ const parseIPAdapter: MetadataParseFunc<IPAdapterConfigMetadata> = async (metada
.parse(await getProperty(metadataItem, 'end_step_percent'));
const ipAdapter: IPAdapterConfigMetadata = {
id: uuidv4(),
type: 'ip_adapter',
isEnabled: true,
model: zModelIdentifierField.parse(ipAdapterModel),
clipVisionModel: 'ViT-H',
controlImage: image?.image_name ?? null,
image: null, //TODO(psyche): need an ImageWithDims
weight: weight ?? initialIPAdapter.weight,
method: method ?? initialIPAdapter.method,
beginStepPct: begin_step_percent ?? initialIPAdapter.beginStepPct,
endStepPct: end_step_percent ?? initialIPAdapter.endStepPct,
beginEndStepPct: [
begin_step_percent ?? initialIPAdapter.beginEndStepPct[0],
end_step_percent ?? initialIPAdapter.beginEndStepPct[1],
],
};
return ipAdapter;
@ -429,16 +387,35 @@ const parseAllIPAdapters: MetadataParseFunc<IPAdapterConfigMetadata[]> = async (
};
//#region Control Layers
const parseLayer: MetadataParseFunc<CanvasRasterLayerState> = (metadataItem) =>
zCanvasRasterLayerState.parseAsync(metadataItem);
const parseLayer: MetadataParseFunc<
| CanvasRasterLayerState
| CanvasControlLayerState
| CanvasIPAdapterState
| CanvasRegionalGuidanceState
| CanvasInpaintMaskState
> = (metadataItem) => zCanvasRasterLayerState.parseAsync(metadataItem);
const parseLayers: MetadataParseFunc<CanvasRasterLayerState[]> = async (metadata) => {
const parseLayers: MetadataParseFunc<
(
| CanvasRasterLayerState
| CanvasControlLayerState
| CanvasIPAdapterState
| CanvasRegionalGuidanceState
| CanvasInpaintMaskState
)[]
> = async (metadata) => {
// We need to support recalling pre-Control Layers metadata into Control Layers. A separate set of parsers handles
// taking pre-CL metadata and parsing it into layers. It doesn't always map 1-to-1, so this is best-effort. For
// example, CL Control Adapters don't support resize mode, so we simply omit that property.
try {
const layers: CanvasRasterLayerState[] = [];
const layers: (
| CanvasRasterLayerState
| CanvasControlLayerState
| CanvasIPAdapterState
| CanvasRegionalGuidanceState
| CanvasInpaintMaskState
)[] = [];
try {
const control_layers = await getProperty(metadata, 'control_layers');
@ -458,7 +435,7 @@ const parseLayers: MetadataParseFunc<CanvasRasterLayerState[]> = async (metadata
controlNetsRaw.map(async (cn) => await parseControlNetToControlAdapterLayer(cn))
);
const controlNetsAsLayers = controlNetsParseResults
.filter((result): result is PromiseFulfilledResult<CanvasControlAdapterState> => result.status === 'fulfilled')
.filter((result): result is PromiseFulfilledResult<CanvasControlLayerState> => result.status === 'fulfilled')
.map((result) => result.value);
layers.push(...controlNetsAsLayers);
} catch {
@ -471,7 +448,7 @@ const parseLayers: MetadataParseFunc<CanvasRasterLayerState[]> = async (metadata
t2iAdaptersRaw.map(async (cn) => await parseT2IAdapterToControlAdapterLayer(cn))
);
const t2iAdaptersAsLayers = t2iAdaptersParseResults
.filter((result): result is PromiseFulfilledResult<CanvasControlAdapterState> => result.status === 'fulfilled')
.filter((result): result is PromiseFulfilledResult<CanvasControlLayerState> => result.status === 'fulfilled')
.map((result) => result.value);
layers.push(...t2iAdaptersAsLayers);
} catch {
@ -491,62 +468,16 @@ const parseLayers: MetadataParseFunc<CanvasRasterLayerState[]> = async (metadata
// no-op
}
try {
const initialImageLayer = await parseInitialImageToInitialImageLayer(metadata);
layers.push(initialImageLayer);
} catch {
// no-op
}
return layers;
} catch {
return [];
}
};
const parseInitialImageToInitialImageLayer: MetadataParseFunc<CanvasRasterLayerState> = async (metadata) => {
// TODO(psyche): recall denoise strength
// const denoisingStrength = await getProperty(metadata, 'strength', isParameterStrength);
const imageName = await getProperty(metadata, 'init_image', isString);
const imageDTO = await getImageDTO(imageName);
assert(imageDTO, 'ImageDTO is null');
const id = getLayerId(uuidv4());
const layer: CanvasRasterLayerState = {
id,
type: 'raster_layer',
bbox: null,
bboxNeedsUpdate: true,
x: 0,
y: 0,
isEnabled: true,
opacity: 1,
objects: [
{
type: 'image',
id: getImageObjectId(id, imageDTO.image_name),
width: imageDTO.width,
height: imageDTO.height,
image: imageDTOToImageWithDims(imageDTO),
x: 0,
y: 0,
},
],
};
return layer;
};
const parseControlNetToControlAdapterLayer: MetadataParseFunc<CanvasControlAdapterState> = async (metadataItem) => {
const parseControlNetToControlAdapterLayer: MetadataParseFunc<CanvasControlLayerState> = async (metadataItem) => {
const control_model = await getProperty(metadataItem, 'control_model');
const key = await getModelKey(control_model, 'controlnet');
const controlNetModel = await fetchModelConfigWithTypeGuard(key, isControlNetModelConfig);
const image = zControlField.shape.image
.nullish()
.catch(null)
.parse(await getProperty(metadataItem, 'image'));
const processedImage = zControlField.shape.image
.nullish()
.catch(null)
.parse(await getProperty(metadataItem, 'processed_image'));
const control_weight = zControlField.shape.control_weight
.nullish()
.catch(null)
@ -564,52 +495,37 @@ const parseControlNetToControlAdapterLayer: MetadataParseFunc<CanvasControlAdapt
.catch(null)
.parse(await getProperty(metadataItem, 'control_mode'));
const defaultPreprocessor = controlNetModel.default_settings?.preprocessor;
const processorConfig = isFilterType(defaultPreprocessor) ? IMAGE_FILTERS[defaultPreprocessor].buildDefaults() : null;
const beginEndStepPct: [number, number] = [
begin_step_percent ?? initialControlNet.beginEndStepPct[0],
end_step_percent ?? initialControlNet.beginEndStepPct[1],
];
const imageDTO = image ? await getImageDTO(image.image_name) : null;
const processedImageDTO = processedImage ? await getImageDTO(processedImage.image_name) : null;
const layer: CanvasControlAdapterState = {
id: getCAId(uuidv4()),
type: 'control_adapter',
bbox: null,
bboxNeedsUpdate: true,
const layer: CanvasControlLayerState = {
id: getPrefixedId('control_layer'),
type: 'control_layer',
isEnabled: true,
opacity: 1,
filter: 'LightnessToAlphaFilter',
x: 0,
y: 0,
adapterType: 'controlnet',
name: null,
objects: [],
position: { x: 0, y: 0 },
withTransparencyEffect: false,
controlAdapter: {
type: 'controlnet',
model: zModelIdentifierField.parse(controlNetModel),
weight: typeof control_weight === 'number' ? control_weight : initialControlNet.weight,
beginEndStepPct,
controlMode: control_mode ?? initialControlNet.controlMode,
image: imageDTO ? imageDTOToImageWithDims(imageDTO) : null,
processedImage: processedImageDTO ? imageDTOToImageWithDims(processedImageDTO) : null,
processorConfig,
processorPendingBatchId: null,
},
};
return layer;
};
const parseT2IAdapterToControlAdapterLayer: MetadataParseFunc<CanvasControlAdapterState> = async (metadataItem) => {
const parseT2IAdapterToControlAdapterLayer: MetadataParseFunc<CanvasControlLayerState> = async (metadataItem) => {
const t2i_adapter_model = await getProperty(metadataItem, 't2i_adapter_model');
const key = await getModelKey(t2i_adapter_model, 't2i_adapter');
const t2iAdapterModel = await fetchModelConfigWithTypeGuard(key, isT2IAdapterModelConfig);
const image = zT2IAdapterField.shape.image
.nullish()
.catch(null)
.parse(await getProperty(metadataItem, 'image'));
const processedImage = zT2IAdapterField.shape.image
.nullish()
.catch(null)
.parse(await getProperty(metadataItem, 'processed_image'));
const weight = zT2IAdapterField.shape.weight
.nullish()
.catch(null)
@ -623,33 +539,26 @@ const parseT2IAdapterToControlAdapterLayer: MetadataParseFunc<CanvasControlAdapt
.catch(null)
.parse(await getProperty(metadataItem, 'end_step_percent'));
const defaultPreprocessor = t2iAdapterModel.default_settings?.preprocessor;
const processorConfig = isFilterType(defaultPreprocessor) ? IMAGE_FILTERS[defaultPreprocessor].buildDefaults() : null;
const beginEndStepPct: [number, number] = [
begin_step_percent ?? initialT2IAdapter.beginEndStepPct[0],
end_step_percent ?? initialT2IAdapter.beginEndStepPct[1],
];
const imageDTO = image ? await getImageDTO(image.image_name) : null;
const processedImageDTO = processedImage ? await getImageDTO(processedImage.image_name) : null;
const layer: CanvasControlAdapterState = {
id: getCAId(uuidv4()),
bbox: null,
bboxNeedsUpdate: true,
const layer: CanvasControlLayerState = {
id: getPrefixedId('control_layer'),
type: 'control_layer',
isEnabled: true,
filter: 'LightnessToAlphaFilter',
opacity: 1,
type: 'control_adapter',
x: 0,
y: 0,
adapterType: 't2i_adapter',
position: { x: 0, y: 0 },
controlAdapter: {
type: 't2i_adapter',
model: zModelIdentifierField.parse(t2iAdapterModel),
weight: typeof weight === 'number' ? weight : initialT2IAdapter.weight,
beginEndStepPct,
image: imageDTO ? imageDTOToImageWithDims(imageDTO) : null,
processedImage: processedImageDTO ? imageDTOToImageWithDims(processedImageDTO) : null,
processorConfig,
processorPendingBatchId: null,
},
name: null,
objects: [],
withTransparencyEffect: false,
};
return layer;
@ -688,15 +597,18 @@ const parseIPAdapterToIPAdapterLayer: MetadataParseFunc<CanvasIPAdapterState> =
const imageDTO = image ? await getImageDTO(image.image_name) : null;
const layer: CanvasIPAdapterState = {
id: getIPAId(uuidv4()),
id: getPrefixedId('ip_adapter'),
type: 'ip_adapter',
isEnabled: true,
name: null,
ipAdapter: {
model: zModelIdentifierField.parse(ipAdapterModel),
weight: typeof weight === 'number' ? weight : initialIPAdapter.weight,
beginEndStepPct,
imageObject: imageDTO ? imageDTOToImageWithDims(imageDTO) : null,
clipVisionModel: initialIPAdapter.clipVisionModel, // TODO: This needs to be added to the zIPAdapterField...
method: method ?? initialIPAdapter.method,
image: imageDTO ? imageDTOToImageWithDims(imageDTO) : null,
},
};
return layer;

View File

@ -1,13 +1,4 @@
import { logger } from 'app/logging/logger';
import { getStore } from 'app/store/nanostores/store';
import { deepClone } from 'common/util/deepClone';
import {
getBrushLineId,
getEraserLineId,
getImageObjectId,
getRectShapeId,
getRGId,
} from 'features/controlLayers/konva/naming';
import {
bboxHeightChanged,
bboxWidthChanged,
@ -17,7 +8,6 @@ import {
negativePromptChanged,
positivePrompt2Changed,
positivePromptChanged,
rasterLayerRecalled,
refinerModelChanged,
setCfgRescaleMultiplier,
setCfgScale,
@ -33,14 +23,9 @@ import {
setSteps,
vaeSelected,
} from 'features/controlLayers/store/canvasV2Slice';
import type { CanvasRasterLayerState, LoRA } from 'features/controlLayers/store/types';
import type { LoRA } from 'features/controlLayers/store/types';
import { setHrfEnabled, setHrfMethod, setHrfStrength } from 'features/hrf/store/hrfSlice';
import type {
ControlNetConfigMetadata,
IPAdapterConfigMetadata,
MetadataRecallFunc,
T2IAdapterConfigMetadata,
} from 'features/metadata/types';
import type { MetadataRecallFunc } from 'features/metadata/types';
import { modelSelected } from 'features/parameters/store/actions';
import type {
ParameterCFGRescaleMultiplier,
@ -64,10 +49,6 @@ import type {
ParameterVAEModel,
ParameterWidth,
} from 'features/parameters/types/parameterSchemas';
import { getImageDTO } from 'services/api/endpoints/images';
import { v4 as uuidv4 } from 'uuid';
const log = logger('metadata');
const recallPositivePrompt: MetadataRecallFunc<ParameterPositivePrompt> = (positivePrompt) => {
getStore().dispatch(positivePromptChanged(positivePrompt));
@ -190,172 +171,6 @@ const recallAllLoRAs: MetadataRecallFunc<LoRA[]> = (loras) => {
});
};
const recallControlNet: MetadataRecallFunc<ControlNetConfigMetadata> = (controlNet) => {
getStore().dispatch(controlAdapterRecalled(controlNet));
};
const recallControlNets: MetadataRecallFunc<ControlNetConfigMetadata[]> = (controlNets) => {
const { dispatch } = getStore();
dispatch(controlNetsReset());
if (!controlNets.length) {
return;
}
controlNets.forEach((controlNet) => {
dispatch(controlAdapterRecalled(controlNet));
});
};
const recallT2IAdapter: MetadataRecallFunc<T2IAdapterConfigMetadata> = (t2iAdapter) => {
getStore().dispatch(controlAdapterRecalled(t2iAdapter));
};
const recallT2IAdapters: MetadataRecallFunc<T2IAdapterConfigMetadata[]> = (t2iAdapters) => {
const { dispatch } = getStore();
dispatch(t2iAdaptersReset());
if (!t2iAdapters.length) {
return;
}
t2iAdapters.forEach((t2iAdapter) => {
dispatch(controlAdapterRecalled(t2iAdapter));
});
};
const recallIPAdapter: MetadataRecallFunc<IPAdapterConfigMetadata> = (ipAdapter) => {
getStore().dispatch(controlAdapterRecalled(ipAdapter));
};
const recallIPAdapters: MetadataRecallFunc<IPAdapterConfigMetadata[]> = (ipAdapters) => {
const { dispatch } = getStore();
dispatch(ipAdaptersReset());
if (!ipAdapters.length) {
return;
}
ipAdapters.forEach((ipAdapter) => {
dispatch(controlAdapterRecalled(ipAdapter));
});
};
// const recallCA: MetadataRecallFunc<CanvasControlAdapterState> = async (ca) => {
// const { dispatch } = getStore();
// const clone = deepClone(ca);
// if (clone.image) {
// const imageDTO = await getImageDTO(clone.image.name);
// if (!imageDTO) {
// clone.image = null;
// }
// }
// if (clone.processedImage) {
// const imageDTO = await getImageDTO(clone.processedImage.name);
// if (!imageDTO) {
// clone.processedImage = null;
// }
// }
// if (clone.model) {
// try {
// await fetchModelConfigByIdentifier(clone.model);
// } catch {
// // MODEL SMITED!
// clone.model = null;
// }
// }
// // No clobber
// clone.id = getCAId(uuidv4());
// // dispatch(caRecalled({ data: clone }));
// return;
// };
// const recallIPA: MetadataRecallFunc<CanvasIPAdapterState> = async (ipa) => {
// const { dispatch } = getStore();
// const clone = deepClone(ipa);
// if (clone.imageObject) {
// const imageDTO = await getImageDTO(clone.imageObject.name);
// if (!imageDTO) {
// clone.imageObject = null;
// }
// }
// if (clone.model) {
// try {
// await fetchModelConfigByIdentifier(clone.model);
// } catch {
// // MODEL SMITED!
// clone.model = null;
// }
// }
// // No clobber
// clone.id = getIPAId(uuidv4());
// dispatch(ipaRecalled({ data: clone }));
// return;
// };
// const recallRG: MetadataRecallFunc<CanvasRegionalGuidanceState> = async (rg) => {
// const { dispatch } = getStore();
// const clone = deepClone(rg);
// // Strip out the uploaded mask image property - this is an intermediate image
// clone.imageCache = null;
// for (const ipAdapter of clone.ipAdapters) {
// if (ipAdapter.imageObject) {
// const imageDTO = await getImageDTO(ipAdapter.imageObject.name);
// if (!imageDTO) {
// ipAdapter.imageObject = null;
// }
// }
// if (ipAdapter.model) {
// try {
// await fetchModelConfigByIdentifier(ipAdapter.model);
// } catch {
// // MODEL SMITED!
// ipAdapter.model = null;
// }
// }
// // No clobber
// ipAdapter.id = uuidv4();
// }
// clone.id = getRGId(uuidv4());
// dispatch(rgRecalled({ data: clone }));
// return;
// };
//#region Control Layers
const recallLayer: MetadataRecallFunc<CanvasRasterLayerState> = async (layer) => {
const { dispatch } = getStore();
const clone = deepClone(layer);
const invalidObjects: string[] = [];
for (const obj of clone.objects) {
if (obj.type === 'image') {
const imageDTO = await getImageDTO(obj.image.image_name);
if (!imageDTO) {
invalidObjects.push(obj.id);
}
}
}
clone.objects = clone.objects.filter(({ id }) => !invalidObjects.includes(id));
for (const obj of clone.objects) {
if (obj.type === 'brush_line') {
obj.id = getBrushLineId(clone.id, uuidv4());
} else if (obj.type === 'eraser_line') {
obj.id = getEraserLineId(clone.id, uuidv4());
} else if (obj.type === 'image') {
obj.id = getImageObjectId(clone.id, uuidv4());
} else if (obj.type === 'rect') {
obj.id = getRectShapeId(clone.id, uuidv4());
} else {
log.error(`Unknown object type ${obj.type}`);
}
}
clone.id = getRGId(uuidv4());
dispatch(rasterLayerRecalled({ data: clone }));
return;
};
const recallLayers: MetadataRecallFunc<CanvasRasterLayerState[]> = (layers) => {
const { dispatch } = getStore();
dispatch(rasterLayerAllDeleted());
for (const l of layers) {
recallLayer(l);
}
};
export const recallers = {
positivePrompt: recallPositivePrompt,
negativePrompt: recallNegativePrompt,
@ -383,12 +198,4 @@ export const recallers = {
vae: recallVAE,
lora: recallLoRA,
loras: recallAllLoRAs,
controlNets: recallControlNets,
controlNet: recallControlNet,
t2iAdapters: recallT2IAdapters,
t2iAdapter: recallT2IAdapter,
ipAdapters: recallIPAdapters,
ipAdapter: recallIPAdapter,
layer: recallLayer,
layers: recallLayers,
} as const;

View File

@ -1,5 +1,5 @@
import { getStore } from 'app/store/nanostores/store';
import type { CanvasRasterLayerState, LoRA } from 'features/controlLayers/store/types';
import type { LoRA } from 'features/controlLayers/store/types';
import type {
ControlNetConfigMetadata,
IPAdapterConfigMetadata,
@ -9,7 +9,6 @@ import type {
import { InvalidModelConfigError } from 'features/metadata/util/modelFetchingHelpers';
import type { ParameterSDXLRefinerModel, ParameterVAEModel } from 'features/parameters/types/parameterSchemas';
import type { BaseModelType } from 'services/api/types';
import { assert } from 'tsafe';
/**
* Checks the given base model type against the currently-selected model's base type and throws an error if they are
@ -21,7 +20,7 @@ const validateBaseCompatibility = (base?: BaseModelType, message?: string) => {
if (!base) {
throw new InvalidModelConfigError(message || 'Missing base');
}
const currentBase = getStore().getState().params.model?.base;
const currentBase = getStore().getState().canvasV2.params.model?.base;
if (currentBase && base !== currentBase) {
throw new InvalidModelConfigError(message || `Incompatible base models: ${base} and ${currentBase}`);
}
@ -129,43 +128,6 @@ const validateIPAdapters: MetadataValidateFunc<IPAdapterConfigMetadata[]> = (ipA
});
};
const validateLayer: MetadataValidateFunc<CanvasRasterLayerState> = (layer) => {
if (layer.type === 'control_adapter_layer') {
const model = layer.controlAdapter.model;
assert(model, 'Control Adapter layer missing model');
validateBaseCompatibility(model.base, 'Layer incompatible with currently-selected model');
}
if (layer.type === 'ip_adapter_layer') {
const model = layer.ipAdapter.model;
assert(model, 'IP Adapter layer missing model');
validateBaseCompatibility(model.base, 'Layer incompatible with currently-selected model');
}
if (layer.type === 'regional_guidance_layer') {
for (const ipa of layer.ipAdapters) {
const model = ipa.model;
assert(model, 'IP Adapter layer missing model');
validateBaseCompatibility(model.base, 'Layer incompatible with currently-selected model');
}
}
return layer;
};
const validateLayers: MetadataValidateFunc<CanvasRasterLayerState[]> = async (layers) => {
const validatedLayers: CanvasRasterLayerState[] = [];
for (const l of layers) {
try {
const validated = await validateLayer(l);
validatedLayers.push(validated);
} catch {
// This is a no-op - we want to continue validating the rest of the layers, and an empty list is valid.
}
}
return new Promise((resolve) => {
resolve(validatedLayers);
});
};
export const validators = {
refinerModel: validateRefinerModel,
vaeModel: validateVAEModel,
@ -177,6 +139,4 @@ export const validators = {
t2iAdapters: validateT2IAdapters,
ipAdapter: validateIPAdapter,
ipAdapters: validateIPAdapters,
layer: validateLayer,
layers: validateLayers,
} as const;

View File

@ -111,21 +111,6 @@ const zParameterLoRAModel = zModelIdentifierField;
export type ParameterLoRAModel = z.infer<typeof zParameterLoRAModel>;
// #endregion
// #region ControlNet Model
const zParameterControlNetModel = zModelIdentifierField;
export type ParameterControlNetModel = z.infer<typeof zParameterControlNetModel>;
// #endregion
// #region IP Adapter Model
const zParameterIPAdapterModel = zModelIdentifierField;
export type ParameterIPAdapterModel = z.infer<typeof zParameterIPAdapterModel>;
// #endregion
// #region T2I Adapter Model
const zParameterT2IAdapterModel = zModelIdentifierField;
export type ParameterT2IAdapterModel = z.infer<typeof zParameterT2IAdapterModel>;
// #endregion
// #region VAE Model
const zParameterSpandrelImageToImageModel = zModelIdentifierField;
export type ParameterSpandrelImageToImageModel = z.infer<typeof zParameterSpandrelImageToImageModel>;