diff --git a/invokeai/app/invocations/compel.py b/invokeai/app/invocations/compel.py index b773f03a8e..563d8d97fd 100644 --- a/invokeai/app/invocations/compel.py +++ b/invokeai/app/invocations/compel.py @@ -279,8 +279,8 @@ class SDXLCompelPromptInvocation(BaseInvocation, SDXLPromptInvocationBase): crop_left: int = InputField(default=0, description="") target_width: int = InputField(default=1024, description="") target_height: int = InputField(default=1024, description="") - clip: ClipField = InputField(description=FieldDescriptions.clip, input=Input.Connection) - clip2: ClipField = InputField(description=FieldDescriptions.clip, input=Input.Connection) + clip: ClipField = InputField(description=FieldDescriptions.clip, input=Input.Connection, title="CLIP 1") + clip2: ClipField = InputField(description=FieldDescriptions.clip, input=Input.Connection, title="CLIP 2") @torch.no_grad() def invoke(self, context: InvocationContext) -> ConditioningOutput: diff --git a/invokeai/app/invocations/metadata.py b/invokeai/app/invocations/metadata.py index 4a968ff3ac..9c028a2dc1 100644 --- a/invokeai/app/invocations/metadata.py +++ b/invokeai/app/invocations/metadata.py @@ -72,10 +72,10 @@ class CoreMetadata(BaseModelExcludeNull): ) refiner_steps: Optional[int] = Field(default=None, description="The number of steps used for the refiner") refiner_scheduler: Optional[str] = Field(default=None, description="The scheduler used for the refiner") - refiner_positive_aesthetic_store: Optional[float] = Field( + refiner_positive_aesthetic_score: Optional[float] = Field( default=None, description="The aesthetic score used for the refiner" ) - refiner_negative_aesthetic_store: Optional[float] = Field( + refiner_negative_aesthetic_score: Optional[float] = Field( default=None, description="The aesthetic score used for the refiner" ) refiner_start: Optional[float] = Field(default=None, description="The start value used for refiner denoising") @@ -160,11 +160,11 @@ class MetadataAccumulatorInvocation(BaseInvocation): default=None, description="The scheduler used for the refiner", ) - refiner_positive_aesthetic_store: Optional[float] = InputField( + refiner_positive_aesthetic_score: Optional[float] = InputField( default=None, description="The aesthetic score used for the refiner", ) - refiner_negative_aesthetic_store: Optional[float] = InputField( + refiner_negative_aesthetic_score: Optional[float] = InputField( default=None, description="The aesthetic score used for the refiner", ) diff --git a/invokeai/app/invocations/model.py b/invokeai/app/invocations/model.py index 548ff3cb4b..5a1073df0a 100644 --- a/invokeai/app/invocations/model.py +++ b/invokeai/app/invocations/model.py @@ -250,13 +250,13 @@ class SDXLLoraLoaderInvocation(BaseInvocation): lora: LoRAModelField = InputField(description=FieldDescriptions.lora_model, input=Input.Direct, title="LoRA") weight: float = InputField(default=0.75, description=FieldDescriptions.lora_weight) - unet: Optional[UNetField] = Field( - default=None, description=FieldDescriptions.unet, input=Input.Connection, title="UNET" + unet: Optional[UNetField] = InputField( + default=None, description=FieldDescriptions.unet, input=Input.Connection, title="UNet" ) - clip: Optional[ClipField] = Field( + clip: Optional[ClipField] = InputField( default=None, description=FieldDescriptions.clip, input=Input.Connection, title="CLIP 1" ) - clip2: Optional[ClipField] = Field( + clip2: Optional[ClipField] = InputField( default=None, description=FieldDescriptions.clip, input=Input.Connection, title="CLIP 2" ) diff --git a/invokeai/backend/model_management/model_probe.py b/invokeai/backend/model_management/model_probe.py index 9f56958366..0d6f61e145 100644 --- a/invokeai/backend/model_management/model_probe.py +++ b/invokeai/backend/model_management/model_probe.py @@ -50,6 +50,7 @@ class ModelProbe(object): "StableDiffusionInpaintPipeline": ModelType.Main, "StableDiffusionXLPipeline": ModelType.Main, "StableDiffusionXLImg2ImgPipeline": ModelType.Main, + "StableDiffusionXLInpaintPipeline": ModelType.Main, "AutoencoderKL": ModelType.Vae, "ControlNetModel": ModelType.ControlNet, } diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx index af5aff52d8..3559679fc4 100644 --- a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx @@ -110,7 +110,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { ); const { metadata, workflow, isLoading } = useGetImageMetadataFromFileQuery( - lastSelectedImage?.image_name ?? skipToken, + lastSelectedImage ?? skipToken, { selectFromResult: (res) => ({ isLoading: res.isFetching, diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx index 272f63fc93..e75a7745bb 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx @@ -52,7 +52,7 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => { const isCanvasEnabled = useFeatureStatus('unifiedCanvas').isFeatureEnabled; const { metadata, workflow, isLoading } = useGetImageMetadataFromFileQuery( - imageDTO.image_name, + imageDTO, { selectFromResult: (res) => ({ isLoading: res.isFetching, diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx index 65d7be454e..e82b03360e 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataActions.tsx @@ -101,13 +101,15 @@ const ImageMetadataActions = (props: Props) => { onClick={handleRecallSeed} /> )} - {metadata.model !== undefined && metadata.model !== null && ( - - )} + {metadata.model !== undefined && + metadata.model !== null && + metadata.model.model_name && ( + + )} {metadata.width && ( { // dispatch(setShouldShowImageDetails(false)); // }); - const { metadata, workflow } = useGetImageMetadataFromFileQuery( - image.image_name, - { - selectFromResult: (res) => ({ - metadata: res?.currentData?.metadata, - workflow: res?.currentData?.workflow, - }), - } - ); + const { metadata, workflow } = useGetImageMetadataFromFileQuery(image, { + selectFromResult: (res) => ({ + metadata: res?.currentData?.metadata, + workflow: res?.currentData?.workflow, + }), + }); return ( ; @@ -770,12 +771,14 @@ export const zCoreMetadata = z steps: z.number().int().nullish(), scheduler: z.string().nullish(), clip_skip: z.number().int().nullish(), - model: zMainOrOnnxModel.nullish(), - controlnets: z.array(zControlField).nullish(), + model: z + .union([zMainModel.deepPartial(), zOnnxModel.deepPartial()]) + .nullish(), + controlnets: z.array(zControlField.deepPartial()).nullish(), loras: z .array( z.object({ - lora: zLoRAModelField, + lora: zLoRAModelField.deepPartial(), weight: z.number(), }) ) @@ -785,15 +788,15 @@ export const zCoreMetadata = z init_image: z.string().nullish(), positive_style_prompt: z.string().nullish(), negative_style_prompt: z.string().nullish(), - refiner_model: zSDXLRefinerModel.nullish(), + refiner_model: zSDXLRefinerModel.deepPartial().nullish(), refiner_cfg_scale: z.number().nullish(), refiner_steps: z.number().int().nullish(), refiner_scheduler: z.string().nullish(), - refiner_positive_aesthetic_store: z.number().nullish(), - refiner_negative_aesthetic_store: z.number().nullish(), + refiner_positive_aesthetic_score: z.number().nullish(), + refiner_negative_aesthetic_score: z.number().nullish(), refiner_start: z.number().nullish(), }) - .catchall(z.record(z.any())); + .passthrough(); export type CoreMetadata = z.infer; @@ -936,22 +939,10 @@ export const zWorkflow = z.object({ }); export const zValidatedWorkflow = zWorkflow.transform((workflow) => { - const nodeTemplates = store.getState().nodes.nodeTemplates; const { nodes, edges } = workflow; const warnings: WorkflowWarning[] = []; const invocationNodes = nodes.filter(isWorkflowInvocationNode); const keyedNodes = keyBy(invocationNodes, 'id'); - invocationNodes.forEach((node, i) => { - const nodeTemplate = nodeTemplates[node.data.type]; - if (!nodeTemplate) { - warnings.push({ - message: `Node "${node.data.label || node.data.id}" skipped`, - issues: [`Unable to find template for type "${node.data.type}"`], - data: node, - }); - delete nodes[i]; - } - }); edges.forEach((edge, i) => { const sourceNode = keyedNodes[edge.source]; const targetNode = keyedNodes[edge.target]; diff --git a/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts b/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts index d44b4a7db1..b46a701757 100644 --- a/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts +++ b/invokeai/frontend/web/src/features/nodes/util/getMetadataAndWorkflowFromImageBlob.ts @@ -1,4 +1,6 @@ import * as png from '@stevebel/png'; +import { logger } from 'app/logging/logger'; +import { parseify } from 'common/util/serialize'; import { ImageMetadataAndWorkflow, zCoreMetadata, @@ -18,6 +20,11 @@ export const getMetadataAndWorkflowFromImageBlob = async ( const metadataResult = zCoreMetadata.safeParse(JSON.parse(rawMetadata)); if (metadataResult.success) { data.metadata = metadataResult.data; + } else { + logger('system').error( + { error: parseify(metadataResult.error) }, + 'Problem reading metadata from image' + ); } } @@ -26,6 +33,11 @@ export const getMetadataAndWorkflowFromImageBlob = async ( const workflowResult = zWorkflow.safeParse(JSON.parse(rawWorkflow)); if (workflowResult.success) { data.workflow = workflowResult.data; + } else { + logger('system').error( + { error: parseify(workflowResult.error) }, + 'Problem reading workflow from image' + ); } } diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts index c9b055dfc2..acee1d5e35 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addSDXLRefinerToGraph.ts @@ -61,9 +61,9 @@ export const addSDXLRefinerToGraph = ( if (metadataAccumulator) { metadataAccumulator.refiner_model = refinerModel; - metadataAccumulator.refiner_positive_aesthetic_store = + metadataAccumulator.refiner_positive_aesthetic_score = refinerPositiveAestheticScore; - metadataAccumulator.refiner_negative_aesthetic_store = + metadataAccumulator.refiner_negative_aesthetic_score = refinerNegativeAestheticScore; metadataAccumulator.refiner_cfg_scale = refinerCFGScale; metadataAccumulator.refiner_scheduler = refinerScheduler; diff --git a/invokeai/frontend/web/src/features/parameters/hooks/useRecallParameters.ts b/invokeai/frontend/web/src/features/parameters/hooks/useRecallParameters.ts index 6794aababc..203ff2cb1b 100644 --- a/invokeai/frontend/web/src/features/parameters/hooks/useRecallParameters.ts +++ b/invokeai/frontend/web/src/features/parameters/hooks/useRecallParameters.ts @@ -341,8 +341,8 @@ export const useRecallParameters = () => { refiner_cfg_scale, refiner_steps, refiner_scheduler, - refiner_positive_aesthetic_store, - refiner_negative_aesthetic_store, + refiner_positive_aesthetic_score, + refiner_negative_aesthetic_score, refiner_start, } = metadata; @@ -403,21 +403,21 @@ export const useRecallParameters = () => { if ( isValidSDXLRefinerPositiveAestheticScore( - refiner_positive_aesthetic_store + refiner_positive_aesthetic_score ) ) { dispatch( - setRefinerPositiveAestheticScore(refiner_positive_aesthetic_store) + setRefinerPositiveAestheticScore(refiner_positive_aesthetic_score) ); } if ( isValidSDXLRefinerNegativeAestheticScore( - refiner_negative_aesthetic_store + refiner_negative_aesthetic_score ) ) { dispatch( - setRefinerNegativeAestheticScore(refiner_negative_aesthetic_store) + setRefinerNegativeAestheticScore(refiner_negative_aesthetic_score) ); } diff --git a/invokeai/frontend/web/src/services/api/endpoints/images.ts b/invokeai/frontend/web/src/services/api/endpoints/images.ts index 62a9b6611e..6b04864815 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/images.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/images.ts @@ -28,6 +28,8 @@ import { } from '../util'; import { boardsApi } from './boards'; import { ImageMetadataAndWorkflow } from 'features/nodes/types/types'; +import { fetchBaseQuery } from '@reduxjs/toolkit/dist/query'; +import { $authToken, $projectId } from '../client'; export const imagesApi = api.injectEndpoints({ endpoints: (build) => ({ @@ -115,18 +117,40 @@ export const imagesApi = api.injectEndpoints({ ], keepUnusedDataFor: 86400, // 24 hours }), - getImageMetadataFromFile: build.query({ - query: (image_name) => ({ - url: `images/i/${image_name}/full`, - responseHandler: async (res) => { - return await res.blob(); - }, - }), - providesTags: (result, error, image_name) => [ - { type: 'ImageMetadataFromFile', id: image_name }, + getImageMetadataFromFile: build.query({ + queryFn: async (args: ImageDTO, api, extraOptions) => { + const authToken = $authToken.get(); + const projectId = $projectId.get(); + const customBaseQuery = fetchBaseQuery({ + baseUrl: '', + prepareHeaders: (headers) => { + if (authToken) { + headers.set('Authorization', `Bearer ${authToken}`); + } + if (projectId) { + headers.set('project-id', projectId); + } + + return headers; + }, + responseHandler: async (res) => { + return await res.blob(); + }, + }); + + const response = await customBaseQuery( + args.image_url, + api, + extraOptions + ); + const data = await getMetadataAndWorkflowFromImageBlob( + response.data as Blob + ); + return { data }; + }, + providesTags: (result, error, image_dto) => [ + { type: 'ImageMetadataFromFile', id: image_dto.image_name }, ], - transformResponse: (response: Blob) => - getMetadataAndWorkflowFromImageBlob(response), keepUnusedDataFor: 86400, // 24 hours }), clearIntermediates: build.mutation({