feat(ui): revised getImageDTO utils

- Rename util to `getImageDTOSafe`
- Update API to accept the same options as RTKQ's `initiate`
- Add `getImageDTO`; while `getImageDTOSafe` returns null if the image is not found, the new util throws
- Update usage of `getImageDTOSafe`
This commit is contained in:
psychedelicious
2024-09-20 18:09:03 +10:00
committed by Kent Keirsey
parent 674e5eb4e5
commit 1644810896
7 changed files with 40 additions and 26 deletions

View File

@@ -14,7 +14,7 @@ import { selectAutoAddBoardId } from 'features/gallery/store/gallerySelectors';
import { atom, computed } from 'nanostores';
import type { Logger } from 'roarr';
import type { UploadOptions } from 'services/api/endpoints/images';
import { getImageDTO, uploadImage } from 'services/api/endpoints/images';
import { getImageDTOSafe, uploadImage } from 'services/api/endpoints/images';
import type { ImageDTO } from 'services/api/types';
import stableHash from 'stable-hash';
import { assert } from 'tsafe';
@@ -210,7 +210,7 @@ export class CanvasCompositorModule extends CanvasModuleBase {
const cachedImageName = this.manager.cache.imageNameCache.get(hash);
if (cachedImageName) {
imageDTO = await getImageDTO(cachedImageName);
imageDTO = await getImageDTOSafe(cachedImageName);
if (imageDTO) {
this.log.trace({ rect, imageName: cachedImageName, imageDTO }, 'Using cached composite raster layer image');
return imageDTO;
@@ -374,7 +374,7 @@ export class CanvasCompositorModule extends CanvasModuleBase {
const cachedImageName = this.manager.cache.imageNameCache.get(hash);
if (cachedImageName) {
imageDTO = await getImageDTO(cachedImageName);
imageDTO = await getImageDTOSafe(cachedImageName);
if (imageDTO) {
this.log.trace({ rect, cachedImageName, imageDTO }, 'Using cached composite inpaint mask image');
return imageDTO;

View File

@@ -27,7 +27,7 @@ import { debounce } from 'lodash-es';
import { atom } from 'nanostores';
import type { Logger } from 'roarr';
import { serializeError } from 'serialize-error';
import { getImageDTO, uploadImage } from 'services/api/endpoints/images';
import { getImageDTOSafe, uploadImage } from 'services/api/endpoints/images';
import type { ImageDTO } from 'services/api/types';
import { assert } from 'tsafe';
@@ -383,7 +383,7 @@ export class CanvasEntityObjectRenderer extends CanvasModuleBase {
const cachedImageName = this.manager.cache.imageNameCache.get(hash);
if (cachedImageName) {
imageDTO = await getImageDTO(cachedImageName);
imageDTO = await getImageDTOSafe(cachedImageName);
if (imageDTO) {
this.log.trace({ rect, cachedImageName, imageDTO }, 'Using cached rasterized image');
return imageDTO;

View File

@@ -11,7 +11,7 @@ import type { CanvasImageState } from 'features/controlLayers/store/types';
import { t } from 'i18next';
import Konva from 'konva';
import type { Logger } from 'roarr';
import { getImageDTO } from 'services/api/endpoints/images';
import { getImageDTOSafe } from 'services/api/endpoints/images';
export class CanvasObjectImage extends CanvasModuleBase {
readonly type = 'object_image';
@@ -100,7 +100,7 @@ export class CanvasObjectImage extends CanvasModuleBase {
this.konva.placeholder.text.text(t('common.loadingImage', 'Loading Image'));
}
const imageDTO = await getImageDTO(imageName);
const imageDTO = await getImageDTOSafe(imageName);
if (imageDTO === null) {
this.onFailedToLoadImage();
return;

View File

@@ -7,7 +7,7 @@ import {
zParameterNegativePrompt,
zParameterPositivePrompt,
} from 'features/parameters/types/parameterSchemas';
import { getImageDTO } from 'services/api/endpoints/images';
import { getImageDTOSafe } from 'services/api/endpoints/images';
import type { ImageDTO } from 'services/api/types';
import { z } from 'zod';
@@ -31,7 +31,7 @@ const zImageWithDims = z
})
.refine(async (v) => {
const { image_name } = v;
const imageDTO = await getImageDTO(image_name, true);
const imageDTO = await getImageDTOSafe(image_name, { forceRefetch: true });
return imageDTO !== null;
});
export type ImageWithDims = z.infer<typeof zImageWithDims>;

View File

@@ -67,7 +67,7 @@ import {
isParameterWidth,
} from 'features/parameters/types/parameterSchemas';
import { get, isArray, isString } from 'lodash-es';
import { getImageDTO } from 'services/api/endpoints/images';
import { getImageDTOSafe } from 'services/api/endpoints/images';
import {
isControlNetModelConfig,
isIPAdapterModelConfig,
@@ -603,7 +603,7 @@ const parseIPAdapterToIPAdapterLayer: MetadataParseFunc<CanvasReferenceImageStat
begin_step_percent ?? initialIPAdapter.beginEndStepPct[0],
end_step_percent ?? initialIPAdapter.beginEndStepPct[1],
];
const imageDTO = image ? await getImageDTO(image.image_name) : null;
const imageDTO = image ? await getImageDTOSafe(image.image_name) : null;
const layer: CanvasReferenceImageState = {
id: getPrefixedId('ip_adapter'),

View File

@@ -1,3 +1,4 @@
import type { StartQueryActionCreatorOptions } from '@reduxjs/toolkit/dist/query/core/buildInitiate';
import { getStore } from 'app/store/nanostores/store';
import type { SerializableObject } from 'common/types';
import type { BoardId } from 'features/gallery/store/types';
@@ -568,25 +569,40 @@ export const {
/**
* Imperative RTKQ helper to fetch an ImageDTO.
* @param image_name The name of the image to fetch
* @param forceRefetch Whether to force a refetch of the image
* @returns
* @param options The options for the query. By default, the query will not subscribe to the store.
* @returns The ImageDTO if found, otherwise null
*/
export const getImageDTO = async (image_name: string, forceRefetch?: boolean): Promise<ImageDTO | null> => {
const options = {
export const getImageDTOSafe = async (
image_name: string,
options?: StartQueryActionCreatorOptions
): Promise<ImageDTO | null> => {
const _options = {
subscribe: false,
forceRefetch,
...options,
};
const req = getStore().dispatch(imagesApi.endpoints.getImageDTO.initiate(image_name, options));
const req = getStore().dispatch(imagesApi.endpoints.getImageDTO.initiate(image_name, _options));
try {
const imageDTO = await req.unwrap();
req.unsubscribe();
return imageDTO;
return await req.unwrap();
} catch {
req.unsubscribe();
return null;
}
};
/**
* Imperative RTKQ helper to fetch an ImageDTO.
* @param image_name The name of the image to fetch
* @param options The options for the query. By default, the query will not subscribe to the store.
* @raises Error if the image is not found or there is an error fetching the image
*/
export const getImageDTO = (image_name: string, options?: StartQueryActionCreatorOptions): Promise<ImageDTO> => {
const _options = {
subscribe: false,
...options,
};
const req = getStore().dispatch(imagesApi.endpoints.getImageDTO.initiate(image_name, _options));
return req.unwrap();
};
export type UploadOptions = {
blob: Blob;
fileName: string;

View File

@@ -7,7 +7,7 @@ import { boardIdSelected, galleryViewChanged, imageSelected, offsetChanged } fro
import { $nodeExecutionStates, upsertExecutionState } from 'features/nodes/hooks/useExecutionState';
import { zNodeStatus } from 'features/nodes/types/invocation';
import { boardsApi } from 'services/api/endpoints/boards';
import { getImageDTO, imagesApi } from 'services/api/endpoints/images';
import { getImageDTOSafe, imagesApi } from 'services/api/endpoints/images';
import type { ImageDTO, S } from 'services/api/types';
import { getCategories, getListImagesUrl } from 'services/api/util';
import { $lastProgressEvent } from 'services/events/stores';
@@ -87,10 +87,8 @@ export const buildOnInvocationComplete = (getState: () => RootState, dispatch: A
const getResultImageDTO = (data: S['InvocationCompleteEvent']) => {
const { result } = data;
if (result.type === 'image_output') {
return getImageDTO(result.image.image_name);
} else if (result.type === 'canvas_v2_mask_and_crop_output') {
return getImageDTO(result.image.image_name);
if (result.type === 'image_output' || result.type === 'canvas_v2_mask_and_crop_output') {
return getImageDTOSafe(result.image.image_name);
}
return null;
};