Skip to content

Commit b700809

Browse files
Maryhipp/option fetch metadata from api (#4491)
## What type of PR is this? (check all applicable) - [ ] Refactor - [x] Feature - [ ] Bug Fix - [ ] Optimization - [ ] Documentation Update - [ ] Community Node Submission ## Description Adds a configuration option to fetch metadata and workflows from api isntead of the image file. Needed for commercial.
2 parents cf83dde + 501cb4c commit b700809

File tree

6 files changed

+73
-21
lines changed

6 files changed

+73
-21
lines changed

invokeai/frontend/web/src/app/types/invokeai.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export type AppConfig = {
4545
* Whether or not we should update image urls when image loading errors
4646
*/
4747
shouldUpdateImagesOnConnect: boolean;
48+
shouldFetchMetadataFromApi: boolean;
4849
disabledTabs: InvokeTabName[];
4950
disabledFeatures: AppFeature[];
5051
disabledSDFeatures: SDFeature[];

invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
setShouldShowImageDetails,
2828
setShouldShowProgressInViewer,
2929
} from 'features/ui/store/uiSlice';
30-
import { memo, useCallback } from 'react';
30+
import { memo, useCallback, useMemo } from 'react';
3131
import { useHotkeys } from 'react-hotkeys-hook';
3232
import { useTranslation } from 'react-i18next';
3333
import {
@@ -49,7 +49,7 @@ import SingleSelectionMenuItems from '../ImageContextMenu/SingleSelectionMenuIte
4949

5050
const currentImageButtonsSelector = createSelector(
5151
[stateSelector, activeTabNameSelector],
52-
({ gallery, system, ui }, activeTabName) => {
52+
({ gallery, system, ui, config }, activeTabName) => {
5353
const { isProcessing, isConnected, shouldConfirmOnDelete, progressImage } =
5454
system;
5555

@@ -59,6 +59,8 @@ const currentImageButtonsSelector = createSelector(
5959
shouldShowProgressInViewer,
6060
} = ui;
6161

62+
const { shouldFetchMetadataFromApi } = config;
63+
6264
const lastSelectedImage = gallery.selection[gallery.selection.length - 1];
6365

6466
return {
@@ -72,6 +74,7 @@ const currentImageButtonsSelector = createSelector(
7274
shouldHidePreview,
7375
shouldShowProgressInViewer,
7476
lastSelectedImage,
77+
shouldFetchMetadataFromApi,
7578
};
7679
},
7780
{
@@ -92,6 +95,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
9295
shouldShowImageDetails,
9396
lastSelectedImage,
9497
shouldShowProgressInViewer,
98+
shouldFetchMetadataFromApi,
9599
} = useAppSelector(currentImageButtonsSelector);
96100

97101
const isUpscalingEnabled = useFeatureStatus('upscaling').isFeatureEnabled;
@@ -106,8 +110,16 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
106110
lastSelectedImage?.image_name ?? skipToken
107111
);
108112

113+
const getMetadataArg = useMemo(() => {
114+
if (lastSelectedImage) {
115+
return { image: lastSelectedImage, shouldFetchMetadataFromApi };
116+
} else {
117+
return skipToken;
118+
}
119+
}, [lastSelectedImage, shouldFetchMetadataFromApi]);
120+
109121
const { metadata, workflow, isLoading } = useGetImageMetadataFromFileQuery(
110-
lastSelectedImage ?? skipToken,
122+
getMetadataArg,
111123
{
112124
selectFromResult: (res) => ({
113125
isLoading: res.isFetching,

invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Flex, MenuItem, Spinner } from '@chakra-ui/react';
22
import { useAppToaster } from 'app/components/Toaster';
3-
import { useAppDispatch } from 'app/store/storeHooks';
3+
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
44
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
55
import {
66
imagesToChangeSelected,
@@ -34,6 +34,7 @@ import {
3434
import { ImageDTO } from 'services/api/types';
3535
import { sentImageToCanvas, sentImageToImg2Img } from '../../store/actions';
3636
import { workflowLoadRequested } from 'features/nodes/store/actions';
37+
import { configSelector } from '../../../system/store/configSelectors';
3738

3839
type SingleSelectionMenuItemsProps = {
3940
imageDTO: ImageDTO;
@@ -48,9 +49,10 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
4849
const toaster = useAppToaster();
4950

5051
const isCanvasEnabled = useFeatureStatus('unifiedCanvas').isFeatureEnabled;
52+
const { shouldFetchMetadataFromApi } = useAppSelector(configSelector);
5153

5254
const { metadata, workflow, isLoading } = useGetImageMetadataFromFileQuery(
53-
imageDTO,
55+
{ image: imageDTO, shouldFetchMetadataFromApi },
5456
{
5557
selectFromResult: (res) => ({
5658
isLoading: res.isFetching,

invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import { useGetImageMetadataFromFileQuery } from 'services/api/endpoints/images'
1515
import { ImageDTO } from 'services/api/types';
1616
import DataViewer from './DataViewer';
1717
import ImageMetadataActions from './ImageMetadataActions';
18+
import { useAppSelector } from '../../../../app/store/storeHooks';
19+
import { configSelector } from '../../../system/store/configSelectors';
1820

1921
type ImageMetadataViewerProps = {
2022
image: ImageDTO;
@@ -27,12 +29,17 @@ const ImageMetadataViewer = ({ image }: ImageMetadataViewerProps) => {
2729
// dispatch(setShouldShowImageDetails(false));
2830
// });
2931

30-
const { metadata, workflow } = useGetImageMetadataFromFileQuery(image, {
31-
selectFromResult: (res) => ({
32-
metadata: res?.currentData?.metadata,
33-
workflow: res?.currentData?.workflow,
34-
}),
35-
});
32+
const { shouldFetchMetadataFromApi } = useAppSelector(configSelector);
33+
34+
const { metadata, workflow } = useGetImageMetadataFromFileQuery(
35+
{ image, shouldFetchMetadataFromApi },
36+
{
37+
selectFromResult: (res) => ({
38+
metadata: res?.currentData?.metadata,
39+
workflow: res?.currentData?.workflow,
40+
}),
41+
}
42+
);
3643

3744
return (
3845
<Flex

invokeai/frontend/web/src/features/system/store/configSlice.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { merge } from 'lodash-es';
55

66
export const initialConfigState: AppConfig = {
77
shouldUpdateImagesOnConnect: false,
8+
shouldFetchMetadataFromApi: false,
89
disabledTabs: [],
910
disabledFeatures: ['lightbox', 'faceRestore', 'batches'],
1011
disabledSDFeatures: [

invokeai/frontend/web/src/services/api/endpoints/images.ts

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
import { EntityState, Update } from '@reduxjs/toolkit';
2+
import { fetchBaseQuery } from '@reduxjs/toolkit/dist/query';
23
import { PatchCollection } from '@reduxjs/toolkit/dist/query/core/buildThunks';
34
import {
45
ASSETS_CATEGORIES,
56
BoardId,
67
IMAGE_CATEGORIES,
78
IMAGE_LIMIT,
89
} from 'features/gallery/store/types';
10+
import {
11+
ImageMetadataAndWorkflow,
12+
zCoreMetadata,
13+
} from 'features/nodes/types/types';
914
import { getMetadataAndWorkflowFromImageBlob } from 'features/nodes/util/getMetadataAndWorkflowFromImageBlob';
1015
import { keyBy } from 'lodash-es';
1116
import { ApiFullTagDescription, LIST_TAG, api } from '..';
17+
import { $authToken, $projectId } from '../client';
1218
import { components, paths } from '../schema';
1319
import {
1420
DeleteBoardResult,
@@ -27,9 +33,6 @@ import {
2733
imagesSelectors,
2834
} from '../util';
2935
import { boardsApi } from './boards';
30-
import { ImageMetadataAndWorkflow } from 'features/nodes/types/types';
31-
import { fetchBaseQuery } from '@reduxjs/toolkit/dist/query';
32-
import { $authToken, $projectId } from '../client';
3336

3437
export const imagesApi = api.injectEndpoints({
3538
endpoints: (build) => ({
@@ -117,8 +120,16 @@ export const imagesApi = api.injectEndpoints({
117120
],
118121
keepUnusedDataFor: 86400, // 24 hours
119122
}),
120-
getImageMetadataFromFile: build.query<ImageMetadataAndWorkflow, ImageDTO>({
121-
queryFn: async (args: ImageDTO, api, extraOptions) => {
123+
getImageMetadataFromFile: build.query<
124+
ImageMetadataAndWorkflow,
125+
{ image: ImageDTO; shouldFetchMetadataFromApi: boolean }
126+
>({
127+
queryFn: async (
128+
args: { image: ImageDTO; shouldFetchMetadataFromApi: boolean },
129+
api,
130+
extraOptions,
131+
fetchWithBaseQuery
132+
) => {
122133
const authToken = $authToken.get();
123134
const projectId = $projectId.get();
124135
const customBaseQuery = fetchBaseQuery({
@@ -139,17 +150,35 @@ export const imagesApi = api.injectEndpoints({
139150
});
140151

141152
const response = await customBaseQuery(
142-
args.image_url,
153+
args.image.image_url,
143154
api,
144155
extraOptions
145156
);
146-
const data = await getMetadataAndWorkflowFromImageBlob(
157+
const blobData = await getMetadataAndWorkflowFromImageBlob(
147158
response.data as Blob
148159
);
149-
return { data };
160+
161+
let metadata = blobData.metadata;
162+
163+
if (args.shouldFetchMetadataFromApi) {
164+
const metadataResponse = await fetchWithBaseQuery(
165+
`images/i/${args.image.image_name}/metadata`
166+
);
167+
if (metadataResponse.data) {
168+
const metadataResult = zCoreMetadata.safeParse(
169+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
170+
(metadataResponse.data as any)?.metadata
171+
);
172+
if (metadataResult.success) {
173+
metadata = metadataResult.data;
174+
}
175+
}
176+
}
177+
178+
return { data: { ...blobData, metadata } };
150179
},
151-
providesTags: (result, error, image_dto) => [
152-
{ type: 'ImageMetadataFromFile', id: image_dto.image_name },
180+
providesTags: (result, error, { image }) => [
181+
{ type: 'ImageMetadataFromFile', id: image.image_name },
153182
],
154183
keepUnusedDataFor: 86400, // 24 hours
155184
}),

0 commit comments

Comments
 (0)