Merge branch 'main' into feat/onnx

This commit is contained in:
Brandon Rising
2023-07-26 10:42:31 -04:00
465 changed files with 14417 additions and 8732 deletions

View File

@ -0,0 +1,16 @@
import { BaseModelType } from './types';
export const ALL_BASE_MODELS: BaseModelType[] = [
'sd-1',
'sd-2',
'sdxl',
'sdxl-refiner',
];
export const NON_REFINER_BASE_MODELS: BaseModelType[] = [
'sd-1',
'sd-2',
'sdxl',
];
export const REFINER_BASE_MODELS: BaseModelType[] = ['sdxl-refiner'];

View File

@ -8,6 +8,7 @@ export const appInfoApi = api.injectEndpoints({
url: `app/version`,
method: 'GET',
}),
providesTags: ['AppVersion'],
keepUnusedDataFor: 86400000, // 1 day
}),
getAppConfig: build.query<AppConfig, void>({
@ -15,6 +16,7 @@ export const appInfoApi = api.injectEndpoints({
url: `app/config`,
method: 'GET',
}),
providesTags: ['AppConfig'],
keepUnusedDataFor: 86400000, // 1 day
}),
}),

View File

@ -1,83 +1,36 @@
import { OffsetPaginatedResults_ImageDTO_ } from 'services/api/types';
import { ApiFullTagDescription, LIST_TAG, api } from '..';
import { paths } from '../schema';
type ListBoardImagesArg =
paths['/api/v1/board_images/{board_id}']['get']['parameters']['path'] &
paths['/api/v1/board_images/{board_id}']['get']['parameters']['query'];
type AddImageToBoardArg =
paths['/api/v1/board_images/']['post']['requestBody']['content']['application/json'];
type RemoveImageFromBoardArg =
paths['/api/v1/board_images/']['delete']['requestBody']['content']['application/json'];
import { api } from '..';
export const boardImagesApi = api.injectEndpoints({
endpoints: (build) => ({
/**
* Board Images Queries
*/
listBoardImages: build.query<
OffsetPaginatedResults_ImageDTO_,
ListBoardImagesArg
>({
query: ({ board_id, offset, limit }) => ({
url: `board_images/${board_id}`,
method: 'GET',
}),
providesTags: (result, error, arg) => {
// any list of boardimages
const tags: ApiFullTagDescription[] = [
{ type: 'BoardImage', id: `${arg.board_id}_${LIST_TAG}` },
];
if (result) {
// and individual tags for each boardimage
tags.push(
...result.items.map(({ board_id, image_name }) => ({
type: 'BoardImage' as const,
id: `${board_id}_${image_name}`,
}))
);
}
return tags;
},
}),
/**
* Board Images Mutations
*/
addImageToBoard: build.mutation<void, AddImageToBoardArg>({
query: ({ board_id, image_name }) => ({
url: `board_images/`,
method: 'POST',
body: { board_id, image_name },
}),
invalidatesTags: (result, error, arg) => [
{ type: 'BoardImage' },
{ type: 'Board', id: arg.board_id },
],
}),
removeImageFromBoard: build.mutation<void, RemoveImageFromBoardArg>({
query: ({ board_id, image_name }) => ({
url: `board_images/`,
method: 'DELETE',
body: { board_id, image_name },
}),
invalidatesTags: (result, error, arg) => [
{ type: 'BoardImage' },
{ type: 'Board', id: arg.board_id },
],
}),
// listBoardImages: build.query<
// OffsetPaginatedResults_ImageDTO_,
// ListBoardImagesArg
// >({
// query: ({ board_id, offset, limit }) => ({
// url: `board_images/${board_id}`,
// method: 'GET',
// }),
// providesTags: (result, error, arg) => {
// // any list of boardimages
// const tags: ApiFullTagDescription[] = [
// { type: 'BoardImage', id: `${arg.board_id}_${LIST_TAG}` },
// ];
// if (result) {
// // and individual tags for each boardimage
// tags.push(
// ...result.items.map(({ board_id, image_name }) => ({
// type: 'BoardImage' as const,
// id: `${board_id}_${image_name}`,
// }))
// );
// }
// return tags;
// },
// }),
}),
});
export const {
useAddImageToBoardMutation,
useRemoveImageFromBoardMutation,
useListBoardImagesQuery,
} = boardImagesApi;
// export const { useListBoardImagesQuery } = boardImagesApi;

View File

@ -1,6 +1,16 @@
import { BoardDTO, OffsetPaginatedResults_BoardDTO_ } from 'services/api/types';
import { Update } from '@reduxjs/toolkit';
import {
ASSETS_CATEGORIES,
IMAGE_CATEGORIES,
} from 'features/gallery/store/types';
import {
BoardDTO,
ImageDTO,
OffsetPaginatedResults_BoardDTO_,
} from 'services/api/types';
import { ApiFullTagDescription, LIST_TAG, api } from '..';
import { paths } from '../schema';
import { getListImagesUrl, imagesAdapter, imagesApi } from './images';
type ListBoardsArg = NonNullable<
paths['/api/v1/boards/']['get']['parameters']['query']
@ -11,6 +21,9 @@ type UpdateBoardArg =
changes: paths['/api/v1/boards/{board_id}']['patch']['requestBody']['content']['application/json'];
};
type DeleteBoardResult =
paths['/api/v1/boards/{board_id}']['delete']['responses']['200']['content']['application/json'];
export const boardsApi = api.injectEndpoints({
endpoints: (build) => ({
/**
@ -59,6 +72,16 @@ export const boardsApi = api.injectEndpoints({
},
}),
listAllImageNamesForBoard: build.query<Array<string>, string>({
query: (board_id) => ({
url: `boards/${board_id}/image_names`,
}),
providesTags: (result, error, arg) => [
{ type: 'ImageNameList', id: arg },
],
keepUnusedDataFor: 0,
}),
/**
* Boards Mutations
*/
@ -82,20 +105,166 @@ export const boardsApi = api.injectEndpoints({
{ type: 'Board', id: arg.board_id },
],
}),
deleteBoard: build.mutation<void, string>({
deleteBoard: build.mutation<DeleteBoardResult, string>({
query: (board_id) => ({ url: `boards/${board_id}`, method: 'DELETE' }),
invalidatesTags: (result, error, arg) => [{ type: 'Board', id: arg }],
invalidatesTags: (result, error, board_id) => [
{ type: 'Board', id: LIST_TAG },
// invalidate the 'No Board' cache
{
type: 'ImageList',
id: getListImagesUrl({
board_id: 'none',
categories: IMAGE_CATEGORIES,
}),
},
{
type: 'ImageList',
id: getListImagesUrl({
board_id: 'none',
categories: ASSETS_CATEGORIES,
}),
},
{ type: 'BoardImagesTotal', id: 'none' },
{ type: 'BoardAssetsTotal', id: 'none' },
],
async onQueryStarted(board_id, { dispatch, queryFulfilled, getState }) {
/**
* Cache changes for deleteBoard:
* - Update every image in the 'getImageDTO' cache that has the board_id
* - Update every image in the 'All Images' cache that has the board_id
* - Update every image in the 'All Assets' cache that has the board_id
* - Invalidate the 'No Board' cache:
* Ideally we'd be able to insert all deleted images into the cache, but we don't
* have access to the deleted images DTOs - only the names, and a network request
* for all of a board's DTOs could be very large. Instead, we invalidate the 'No Board'
* cache.
*/
try {
const { data } = await queryFulfilled;
const { deleted_board_images } = data;
// update getImageDTO caches
deleted_board_images.forEach((image_id) => {
dispatch(
imagesApi.util.updateQueryData(
'getImageDTO',
image_id,
(draft) => {
draft.board_id = undefined;
}
)
);
});
// update 'All Images' & 'All Assets' caches
const queryArgsToUpdate = [
{
categories: IMAGE_CATEGORIES,
},
{
categories: ASSETS_CATEGORIES,
},
];
const updates: Update<ImageDTO>[] = deleted_board_images.map(
(image_name) => ({
id: image_name,
changes: { board_id: undefined },
})
);
queryArgsToUpdate.forEach((queryArgs) => {
dispatch(
imagesApi.util.updateQueryData(
'listImages',
queryArgs,
(draft) => {
const oldTotal = draft.total;
const newState = imagesAdapter.updateMany(draft, updates);
const delta = newState.total - oldTotal;
draft.total = draft.total + delta;
}
)
);
});
} catch {
//no-op
}
},
}),
deleteBoardAndImages: build.mutation<void, string>({
deleteBoardAndImages: build.mutation<DeleteBoardResult, string>({
query: (board_id) => ({
url: `boards/${board_id}`,
method: 'DELETE',
params: { include_images: true },
}),
invalidatesTags: (result, error, arg) => [
{ type: 'Board', id: arg },
{ type: 'Image', id: LIST_TAG },
invalidatesTags: (result, error, board_id) => [
{ type: 'Board', id: LIST_TAG },
{
type: 'ImageList',
id: getListImagesUrl({
board_id: 'none',
categories: IMAGE_CATEGORIES,
}),
},
{
type: 'ImageList',
id: getListImagesUrl({
board_id: 'none',
categories: ASSETS_CATEGORIES,
}),
},
{ type: 'BoardImagesTotal', id: 'none' },
{ type: 'BoardAssetsTotal', id: 'none' },
],
async onQueryStarted(board_id, { dispatch, queryFulfilled, getState }) {
/**
* Cache changes for deleteBoardAndImages:
* - ~~Remove every image in the 'getImageDTO' cache that has the board_id~~
* This isn't actually possible, you cannot remove cache entries with RTK Query.
* Instead, we rely on the UI to remove all components that use the deleted images.
* - Remove every image in the 'All Images' cache that has the board_id
* - Remove every image in the 'All Assets' cache that has the board_id
*/
try {
const { data } = await queryFulfilled;
const { deleted_images } = data;
// update 'All Images' & 'All Assets' caches
const queryArgsToUpdate = [
{
categories: IMAGE_CATEGORIES,
},
{
categories: ASSETS_CATEGORIES,
},
];
queryArgsToUpdate.forEach((queryArgs) => {
dispatch(
imagesApi.util.updateQueryData(
'listImages',
queryArgs,
(draft) => {
const oldTotal = draft.total;
const newState = imagesAdapter.removeMany(
draft,
deleted_images
);
const delta = newState.total - oldTotal;
draft.total = draft.total + delta;
}
)
);
});
} catch {
//no-op
}
},
}),
}),
});
@ -107,4 +276,5 @@ export const {
useUpdateBoardMutation,
useDeleteBoardMutation,
useDeleteBoardAndImagesMutation,
useListAllImageNamesForBoardQuery,
} = boardsApi;

View File

@ -1,6 +1,55 @@
import { EntityState, createEntityAdapter } from '@reduxjs/toolkit';
import { PatchCollection } from '@reduxjs/toolkit/dist/query/core/buildThunks';
import { dateComparator } from 'common/util/dateComparator';
import {
ASSETS_CATEGORIES,
BoardId,
IMAGE_CATEGORIES,
} from 'features/gallery/store/types';
import queryString from 'query-string';
import { ApiFullTagDescription, api } from '..';
import { components } from '../schema';
import { ImageDTO } from '../types';
import { components, paths } from '../schema';
import {
ImageCategory,
ImageDTO,
OffsetPaginatedResults_ImageDTO_,
PostUploadAction,
} from '../types';
const getIsImageInDateRange = (
data: ImageCache | undefined,
imageDTO: ImageDTO
) => {
if (!data) {
return false;
}
const cacheImageDTOS = imagesSelectors.selectAll(data);
if (cacheImageDTOS.length > 1) {
// Images are sorted by `created_at` DESC
// check if the image is newer than the oldest image in the cache
const createdDate = new Date(imageDTO.created_at);
const oldestDate = new Date(
cacheImageDTOS[cacheImageDTOS.length - 1].created_at
);
return createdDate >= oldestDate;
} else if ([0, 1].includes(cacheImageDTOS.length)) {
// if there are only 1 or 0 images in the cache, we consider the image to be in the date range
return true;
}
return false;
};
const getCategories = (imageDTO: ImageDTO) => {
if (IMAGE_CATEGORIES.includes(imageDTO.image_category)) {
return IMAGE_CATEGORIES;
}
return ASSETS_CATEGORIES;
};
export type ListImagesArgs = NonNullable<
paths['/api/v1/images/']['get']['parameters']['query']
>;
/**
* This is an unsafe type; the object inside is not guaranteed to be valid.
@ -10,11 +59,107 @@ export type UnsafeImageMetadata = {
graph: NonNullable<components['schemas']['Graph']>;
};
export type ImageCache = EntityState<ImageDTO> & { total: number };
// The adapter is not actually the data store - it just provides helper functions to interact
// with some other store of data. We will use the RTK Query cache as that store.
export const imagesAdapter = createEntityAdapter<ImageDTO>({
selectId: (image) => image.image_name,
sortComparer: (a, b) => dateComparator(b.updated_at, a.updated_at),
});
// We want to also store the images total in the cache. When we initialize the cache state,
// we will provide this type arg so the adapter knows we want the total.
export type AdditionalImagesAdapterState = { total: number };
// Create selectors for the adapter.
export const imagesSelectors = imagesAdapter.getSelectors();
// Helper to create the url for the listImages endpoint. Also we use it to create the cache key.
export const getListImagesUrl = (queryArgs: ListImagesArgs) =>
`images/?${queryString.stringify(queryArgs, { arrayFormat: 'none' })}`;
export const imagesApi = api.injectEndpoints({
endpoints: (build) => ({
/**
* Image Queries
*/
listImages: build.query<
EntityState<ImageDTO> & { total: number },
ListImagesArgs
>({
query: (queryArgs) => ({
// Use the helper to create the URL.
url: getListImagesUrl(queryArgs),
method: 'GET',
}),
providesTags: (result, error, { board_id, categories }) => [
// Make the tags the same as the cache key
{ type: 'ImageList', id: getListImagesUrl({ board_id, categories }) },
],
serializeQueryArgs: ({ queryArgs }) => {
// Create cache & key based on board_id and categories - skip the other args.
// Offset is the size of the cache, and limit is always the same. Both are provided by
// the consumer of the query.
const { board_id, categories } = queryArgs;
// Just use the same fn used to create the url; it makes an understandable cache key.
// This cache key is the same for any combo of board_id and categories, doesn't change
// when offset & limit change.
const cacheKey = getListImagesUrl({ board_id, categories });
return cacheKey;
},
transformResponse(response: OffsetPaginatedResults_ImageDTO_) {
const { total, items: images } = response;
// Use the adapter to convert the response to the right shape, and adding the new total.
// The trick is to just provide an empty state and add the images array to it. This returns
// a properly shaped EntityState.
return imagesAdapter.addMany(
imagesAdapter.getInitialState<AdditionalImagesAdapterState>({
total,
}),
images
);
},
merge: (cache, response) => {
// Here we actually update the cache. `response` here is the output of `transformResponse`
// above. In a similar vein to `transformResponse`, we can use the imagesAdapter to get
// things in the right shape. Also update the total image count.
imagesAdapter.addMany(cache, imagesSelectors.selectAll(response));
cache.total = response.total;
},
forceRefetch({ currentArg, previousArg }) {
// Refetch when the offset changes (which means we are on a new page).
return currentArg?.offset !== previousArg?.offset;
},
async onQueryStarted(_, { dispatch, queryFulfilled }) {
try {
const { data } = await queryFulfilled;
// update the `getImageDTO` cache for each image
imagesSelectors.selectAll(data).forEach((imageDTO) => {
dispatch(
imagesApi.util.upsertQueryData(
'getImageDTO',
imageDTO.image_name,
imageDTO
)
);
});
} catch {
// no-op
}
},
// 24 hours - reducing this to a few minutes would reduce memory usage.
keepUnusedDataFor: 86400,
}),
getIntermediatesCount: build.query<number, void>({
query: () => ({ url: getListImagesUrl({ is_intermediate: true }) }),
providesTags: ['IntermediatesCount'],
transformResponse: (response: OffsetPaginatedResults_ImageDTO_) => {
return response.total;
},
}),
getImageDTO: build.query<ImageDTO, string>({
query: (image_name) => ({ url: `images/${image_name}` }),
providesTags: (result, error, arg) => {
@ -36,7 +181,617 @@ export const imagesApi = api.injectEndpoints({
},
keepUnusedDataFor: 86400, // 24 hours
}),
getBoardImagesTotal: build.query<number, string | undefined>({
query: (board_id) => ({
url: getListImagesUrl({
board_id: board_id ?? 'none',
categories: IMAGE_CATEGORIES,
is_intermediate: false,
limit: 0,
offset: 0,
}),
method: 'GET',
}),
providesTags: (result, error, arg) => [
{ type: 'BoardImagesTotal', id: arg ?? 'none' },
],
transformResponse: (response: OffsetPaginatedResults_ImageDTO_) => {
return response.total;
},
}),
getBoardAssetsTotal: build.query<number, string | undefined>({
query: (board_id) => ({
url: getListImagesUrl({
board_id: board_id ?? 'none',
categories: ASSETS_CATEGORIES,
is_intermediate: false,
limit: 0,
offset: 0,
}),
method: 'GET',
}),
providesTags: (result, error, arg) => [
{ type: 'BoardAssetsTotal', id: arg ?? 'none' },
],
transformResponse: (response: OffsetPaginatedResults_ImageDTO_) => {
return response.total;
},
}),
clearIntermediates: build.mutation<number, void>({
query: () => ({ url: `images/clear-intermediates`, method: 'POST' }),
invalidatesTags: ['IntermediatesCount'],
}),
deleteImage: build.mutation<void, ImageDTO>({
query: ({ image_name }) => ({
url: `images/${image_name}`,
method: 'DELETE',
}),
invalidatesTags: (result, error, { board_id }) => [
{ type: 'BoardImagesTotal', id: board_id ?? 'none' },
{ type: 'BoardAssetsTotal', id: board_id ?? 'none' },
],
async onQueryStarted(imageDTO, { dispatch, queryFulfilled }) {
/**
* Cache changes for `deleteImage`:
* - NOT POSSIBLE: *remove* from getImageDTO
* - $cache = [board_id|no_board]/[images|assets]
* - *remove* from $cache
*/
const { image_name, board_id } = imageDTO;
// Store patches so we can undo if the query fails
const patches: PatchCollection[] = [];
// determine `categories`, i.e. do we update "All Images" or "All Assets"
// $cache = [board_id|no_board]/[images|assets]
const categories = getCategories(imageDTO);
// *remove* from $cache
patches.push(
dispatch(
imagesApi.util.updateQueryData(
'listImages',
{ board_id: board_id ?? 'none', categories },
(draft) => {
const oldTotal = draft.total;
const newState = imagesAdapter.removeOne(draft, image_name);
const delta = newState.total - oldTotal;
draft.total = draft.total + delta;
}
)
)
);
try {
await queryFulfilled;
} catch {
patches.forEach((patchResult) => patchResult.undo());
}
},
}),
/**
* Change an image's `is_intermediate` property.
*/
changeImageIsIntermediate: build.mutation<
ImageDTO,
{ imageDTO: ImageDTO; is_intermediate: boolean }
>({
query: ({ imageDTO, is_intermediate }) => ({
url: `images/${imageDTO.image_name}`,
method: 'PATCH',
body: { is_intermediate },
}),
invalidatesTags: (result, error, { imageDTO }) => [
{ type: 'BoardImagesTotal', id: imageDTO.board_id ?? 'none' },
{ type: 'BoardAssetsTotal', id: imageDTO.board_id ?? 'none' },
],
async onQueryStarted(
{ imageDTO, is_intermediate },
{ dispatch, queryFulfilled, getState }
) {
/**
* Cache changes for `changeImageIsIntermediate`:
* - *update* getImageDTO
* - $cache = [board_id|no_board]/[images|assets]
* - IF it is being changed to an intermediate:
* - remove from $cache
* - ELSE (it is being changed to a non-intermediate):
* - IF it eligible for insertion into existing $cache:
* - *upsert* to $cache
*/
// Store patches so we can undo if the query fails
const patches: PatchCollection[] = [];
// *update* getImageDTO
patches.push(
dispatch(
imagesApi.util.updateQueryData(
'getImageDTO',
imageDTO.image_name,
(draft) => {
Object.assign(draft, { is_intermediate });
}
)
)
);
// $cache = [board_id|no_board]/[images|assets]
const categories = getCategories(imageDTO);
if (is_intermediate) {
// IF it is being changed to an intermediate:
// remove from $cache
patches.push(
dispatch(
imagesApi.util.updateQueryData(
'listImages',
{ board_id: imageDTO.board_id ?? 'none', categories },
(draft) => {
const oldTotal = draft.total;
const newState = imagesAdapter.removeOne(
draft,
imageDTO.image_name
);
const delta = newState.total - oldTotal;
draft.total = draft.total + delta;
}
)
)
);
} else {
// ELSE (it is being changed to a non-intermediate):
console.log(imageDTO);
const queryArgs = {
board_id: imageDTO.board_id ?? 'none',
categories,
};
const currentCache = imagesApi.endpoints.listImages.select(queryArgs)(
getState()
);
// IF it eligible for insertion into existing $cache
// "eligible" means either:
// - The cache is fully populated, with all images in the db cached
// OR
// - The image's `created_at` is within the range of the cached images
const isCacheFullyPopulated =
currentCache.data &&
currentCache.data.ids.length >= currentCache.data.total;
const isInDateRange = getIsImageInDateRange(
currentCache.data,
imageDTO
);
if (isCacheFullyPopulated || isInDateRange) {
// *upsert* to $cache
patches.push(
dispatch(
imagesApi.util.updateQueryData(
'listImages',
queryArgs,
(draft) => {
const oldTotal = draft.total;
const newState = imagesAdapter.upsertOne(draft, imageDTO);
const delta = newState.total - oldTotal;
draft.total = draft.total + delta;
}
)
)
);
}
}
try {
await queryFulfilled;
} catch {
patches.forEach((patchResult) => patchResult.undo());
}
},
}),
/**
* Change an image's `session_id` association.
*/
changeImageSessionId: build.mutation<
ImageDTO,
{ imageDTO: ImageDTO; session_id: string }
>({
query: ({ imageDTO, session_id }) => ({
url: `images/${imageDTO.image_name}`,
method: 'PATCH',
body: { session_id },
}),
invalidatesTags: (result, error, { imageDTO }) => [
{ type: 'BoardImagesTotal', id: imageDTO.board_id ?? 'none' },
{ type: 'BoardAssetsTotal', id: imageDTO.board_id ?? 'none' },
],
async onQueryStarted(
{ imageDTO, session_id },
{ dispatch, queryFulfilled, getState }
) {
/**
* Cache changes for `changeImageSessionId`:
* - *update* getImageDTO
*/
// Store patches so we can undo if the query fails
const patches: PatchCollection[] = [];
// *update* getImageDTO
patches.push(
dispatch(
imagesApi.util.updateQueryData(
'getImageDTO',
imageDTO.image_name,
(draft) => {
Object.assign(draft, { session_id });
}
)
)
);
try {
await queryFulfilled;
} catch {
patches.forEach((patchResult) => patchResult.undo());
}
},
}),
uploadImage: build.mutation<
ImageDTO,
{
file: File;
image_category: ImageCategory;
is_intermediate: boolean;
postUploadAction?: PostUploadAction;
session_id?: string;
board_id?: string;
crop_visible?: boolean;
}
>({
query: ({
file,
image_category,
is_intermediate,
session_id,
board_id,
crop_visible,
}) => {
const formData = new FormData();
formData.append('file', file);
return {
url: `images/`,
method: 'POST',
body: formData,
params: {
image_category,
is_intermediate,
session_id,
board_id,
crop_visible,
},
};
},
async onQueryStarted(
{
file,
image_category,
is_intermediate,
postUploadAction,
session_id,
board_id,
},
{ dispatch, queryFulfilled }
) {
try {
/**
* NOTE: PESSIMISTIC UPDATE
* Cache changes for `uploadImage`:
* - IF the image is an intermediate:
* - BAIL OUT
* - *add* to `getImageDTO`
* - *add* to no_board/assets
*/
const { data: imageDTO } = await queryFulfilled;
if (imageDTO.is_intermediate) {
// Don't add it to anything
return;
}
// *add* to `getImageDTO`
dispatch(
imagesApi.util.upsertQueryData(
'getImageDTO',
imageDTO.image_name,
imageDTO
)
);
const categories = getCategories(imageDTO);
// *add* to no_board/assets
dispatch(
imagesApi.util.updateQueryData(
'listImages',
{
board_id: imageDTO.board_id ?? 'none',
categories,
},
(draft) => {
const oldTotal = draft.total;
const newState = imagesAdapter.addOne(draft, imageDTO);
const delta = newState.total - oldTotal;
draft.total = draft.total + delta;
}
)
);
dispatch(
imagesApi.util.invalidateTags([
{ type: 'BoardImagesTotal', id: imageDTO.board_id ?? 'none' },
{ type: 'BoardAssetsTotal', id: imageDTO.board_id ?? 'none' },
])
);
} catch {
// query failed, no action needed
}
},
}),
addImageToBoard: build.mutation<
void,
{ board_id: BoardId; imageDTO: ImageDTO }
>({
query: ({ board_id, imageDTO }) => {
const { image_name } = imageDTO;
return {
url: `board_images/`,
method: 'POST',
body: { board_id, image_name },
};
},
invalidatesTags: (result, error, { board_id, imageDTO }) => [
{ type: 'Board', id: board_id },
{ type: 'BoardImagesTotal', id: board_id },
{ type: 'BoardImagesTotal', id: imageDTO.board_id ?? 'none' },
{ type: 'BoardAssetsTotal', id: board_id },
{ type: 'BoardAssetsTotal', id: imageDTO.board_id ?? 'none' },
],
async onQueryStarted(
{ board_id, imageDTO },
{ dispatch, queryFulfilled, getState }
) {
/**
* Cache changes for `addImageToBoard`:
* - *update* getImageDTO
* - IF it is intermediate:
* - BAIL OUT ON FURTHER CHANGES
* - IF it has an old board_id:
* - THEN *remove* from old board_id/[images|assets]
* - ELSE *remove* from no_board/[images|assets]
* - $cache = board_id/[images|assets]
* - IF it eligible for insertion into existing $cache:
* - THEN *add* to $cache
*/
const patches: PatchCollection[] = [];
const categories = getCategories(imageDTO);
// *update* getImageDTO
patches.push(
dispatch(
imagesApi.util.updateQueryData(
'getImageDTO',
imageDTO.image_name,
(draft) => {
Object.assign(draft, { board_id });
}
)
)
);
if (!imageDTO.is_intermediate) {
// *remove* from [no_board|board_id]/[images|assets]
patches.push(
dispatch(
imagesApi.util.updateQueryData(
'listImages',
{
board_id: imageDTO.board_id ?? 'none',
categories,
},
(draft) => {
const oldTotal = draft.total;
const newState = imagesAdapter.removeOne(
draft,
imageDTO.image_name
);
const delta = newState.total - oldTotal;
draft.total = draft.total + delta;
}
)
)
);
// $cache = board_id/[images|assets]
const queryArgs = { board_id: board_id ?? 'none', categories };
const currentCache = imagesApi.endpoints.listImages.select(queryArgs)(
getState()
);
// IF it eligible for insertion into existing $cache
// "eligible" means either:
// - The cache is fully populated, with all images in the db cached
// OR
// - The image's `created_at` is within the range of the cached images
const isCacheFullyPopulated =
currentCache.data &&
currentCache.data.ids.length >= currentCache.data.total;
const isInDateRange = getIsImageInDateRange(
currentCache.data,
imageDTO
);
if (isCacheFullyPopulated || isInDateRange) {
// THEN *add* to $cache
patches.push(
dispatch(
imagesApi.util.updateQueryData(
'listImages',
queryArgs,
(draft) => {
const oldTotal = draft.total;
const newState = imagesAdapter.addOne(draft, imageDTO);
const delta = newState.total - oldTotal;
draft.total = draft.total + delta;
}
)
)
);
}
}
try {
await queryFulfilled;
} catch {
patches.forEach((patchResult) => patchResult.undo());
}
},
}),
removeImageFromBoard: build.mutation<void, { imageDTO: ImageDTO }>({
query: ({ imageDTO }) => {
const { board_id, image_name } = imageDTO;
return {
url: `board_images/`,
method: 'DELETE',
body: { board_id, image_name },
};
},
invalidatesTags: (result, error, { imageDTO }) => [
{ type: 'Board', id: imageDTO.board_id },
{ type: 'BoardImagesTotal', id: imageDTO.board_id },
{ type: 'BoardImagesTotal', id: 'none' },
{ type: 'BoardAssetsTotal', id: imageDTO.board_id },
{ type: 'BoardAssetsTotal', id: 'none' },
],
async onQueryStarted(
{ imageDTO },
{ dispatch, queryFulfilled, getState }
) {
/**
* Cache changes for removeImageFromBoard:
* - *update* getImageDTO
* - *remove* from board_id/[images|assets]
* - $cache = no_board/[images|assets]
* - IF it eligible for insertion into existing $cache:
* - THEN *upsert* to $cache
*/
const categories = getCategories(imageDTO);
const patches: PatchCollection[] = [];
// *update* getImageDTO
patches.push(
dispatch(
imagesApi.util.updateQueryData(
'getImageDTO',
imageDTO.image_name,
(draft) => {
Object.assign(draft, { board_id: undefined });
}
)
)
);
// *remove* from board_id/[images|assets]
patches.push(
dispatch(
imagesApi.util.updateQueryData(
'listImages',
{
board_id: imageDTO.board_id ?? 'none',
categories,
},
(draft) => {
const oldTotal = draft.total;
const newState = imagesAdapter.removeOne(
draft,
imageDTO.image_name
);
const delta = newState.total - oldTotal;
draft.total = draft.total + delta;
}
)
)
);
// $cache = no_board/[images|assets]
const queryArgs = { board_id: 'none', categories };
const currentCache = imagesApi.endpoints.listImages.select(queryArgs)(
getState()
);
// IF it eligible for insertion into existing $cache
// "eligible" means either:
// - The cache is fully populated, with all images in the db cached
// OR
// - The image's `created_at` is within the range of the cached images
const isCacheFullyPopulated =
currentCache.data &&
currentCache.data.ids.length >= currentCache.data.total;
const isInDateRange = getIsImageInDateRange(
currentCache.data,
imageDTO
);
if (isCacheFullyPopulated || isInDateRange) {
// THEN *upsert* to $cache
patches.push(
dispatch(
imagesApi.util.updateQueryData(
'listImages',
queryArgs,
(draft) => {
const oldTotal = draft.total;
const newState = imagesAdapter.upsertOne(draft, imageDTO);
const delta = newState.total - oldTotal;
draft.total = draft.total + delta;
}
)
)
);
}
try {
await queryFulfilled;
} catch {
patches.forEach((patchResult) => patchResult.undo());
}
},
}),
}),
});
export const { useGetImageDTOQuery, useGetImageMetadataQuery } = imagesApi;
export const {
useGetIntermediatesCountQuery,
useListImagesQuery,
useLazyListImagesQuery,
useGetImageDTOQuery,
useGetImageMetadataQuery,
useDeleteImageMutation,
useGetBoardImagesTotalQuery,
useGetBoardAssetsTotalQuery,
useUploadImageMutation,
useAddImageToBoardMutation,
useRemoveImageFromBoardMutation,
useClearIntermediatesMutation,
} = imagesApi;

View File

@ -97,6 +97,9 @@ type AddMainModelArg = {
type AddMainModelResponse =
paths['/api/v1/models/add']['post']['responses']['201']['content']['application/json'];
type SyncModelsResponse =
paths['/api/v1/models/sync']['post']['responses']['201']['content']['application/json'];
export type SearchFolderResponse =
paths['/api/v1/models/search']['get']['responses']['200']['content']['application/json'];
@ -181,8 +184,19 @@ export const modelsApi = api.injectEndpoints({
);
},
}),
getMainModels: build.query<EntityState<MainModelConfigEntity>, void>({
query: () => ({ url: 'models/', params: { model_type: 'main' } }),
getMainModels: build.query<
EntityState<MainModelConfigEntity>,
BaseModelType[]
>({
query: (base_models) => {
const params = {
model_type: 'main',
base_models,
};
const query = queryString.stringify(params, { arrayFormat: 'none' });
return `models/?${query}`;
},
providesTags: (result, error, arg) => {
const tags: ApiFullTagDescription[] = [
{ type: 'MainModel', id: LIST_TAG },
@ -224,7 +238,10 @@ export const modelsApi = api.injectEndpoints({
body: body,
};
},
invalidatesTags: [{ type: 'MainModel', id: LIST_TAG }],
invalidatesTags: [
{ type: 'MainModel', id: LIST_TAG },
{ type: 'SDXLRefinerModel', id: LIST_TAG },
],
}),
importMainModels: build.mutation<
ImportMainModelResponse,
@ -237,7 +254,10 @@ export const modelsApi = api.injectEndpoints({
body: body,
};
},
invalidatesTags: [{ type: 'MainModel', id: LIST_TAG }],
invalidatesTags: [
{ type: 'MainModel', id: LIST_TAG },
{ type: 'SDXLRefinerModel', id: LIST_TAG },
],
}),
addMainModels: build.mutation<AddMainModelResponse, AddMainModelArg>({
query: ({ body }) => {
@ -247,7 +267,10 @@ export const modelsApi = api.injectEndpoints({
body: body,
};
},
invalidatesTags: [{ type: 'MainModel', id: LIST_TAG }],
invalidatesTags: [
{ type: 'MainModel', id: LIST_TAG },
{ type: 'SDXLRefinerModel', id: LIST_TAG },
],
}),
deleteMainModels: build.mutation<
DeleteMainModelResponse,
@ -259,7 +282,10 @@ export const modelsApi = api.injectEndpoints({
method: 'DELETE',
};
},
invalidatesTags: [{ type: 'MainModel', id: LIST_TAG }],
invalidatesTags: [
{ type: 'MainModel', id: LIST_TAG },
{ type: 'SDXLRefinerModel', id: LIST_TAG },
],
}),
convertMainModels: build.mutation<
ConvertMainModelResponse,
@ -272,7 +298,10 @@ export const modelsApi = api.injectEndpoints({
params: params,
};
},
invalidatesTags: [{ type: 'MainModel', id: LIST_TAG }],
invalidatesTags: [
{ type: 'MainModel', id: LIST_TAG },
{ type: 'SDXLRefinerModel', id: LIST_TAG },
],
}),
mergeMainModels: build.mutation<MergeMainModelResponse, MergeMainModelArg>({
query: ({ base_model, body }) => {
@ -282,7 +311,22 @@ export const modelsApi = api.injectEndpoints({
body: body,
};
},
invalidatesTags: [{ type: 'MainModel', id: LIST_TAG }],
invalidatesTags: [
{ type: 'MainModel', id: LIST_TAG },
{ type: 'SDXLRefinerModel', id: LIST_TAG },
],
}),
syncModels: build.mutation<SyncModelsResponse, void>({
query: () => {
return {
url: `models/sync`,
method: 'POST',
};
},
invalidatesTags: [
{ type: 'MainModel', id: LIST_TAG },
{ type: 'SDXLRefinerModel', id: LIST_TAG },
],
}),
getLoRAModels: build.query<EntityState<LoRAModelConfigEntity>, void>({
query: () => ({ url: 'models/', params: { model_type: 'lora' } }),
@ -464,6 +508,7 @@ export const {
useAddMainModelsMutation,
useConvertMainModelsMutation,
useMergeMainModelsMutation,
useSyncModelsMutation,
useGetModelsInFolderQuery,
useGetCheckpointConfigsQuery,
} = modelsApi;

View File

@ -0,0 +1,15 @@
import { BoardId } from 'features/gallery/store/types';
import { useListAllBoardsQuery } from '../endpoints/boards';
export const useBoardName = (board_id: BoardId | null | undefined) => {
const { boardName } = useListAllBoardsQuery(undefined, {
selectFromResult: ({ data }) => {
const selectedBoard = data?.find((b) => b.board_id === board_id);
const boardName = selectedBoard?.board_name || 'Uncategorized';
return { boardName };
},
});
return boardName;
};

View File

@ -0,0 +1,21 @@
import { useAppSelector } from 'app/store/storeHooks';
import { BoardId } from 'features/gallery/store/types';
import { useMemo } from 'react';
import {
useGetBoardAssetsTotalQuery,
useGetBoardImagesTotalQuery,
} from '../endpoints/images';
export const useBoardTotal = (board_id: BoardId) => {
const galleryView = useAppSelector((state) => state.gallery.galleryView);
const { data: totalImages } = useGetBoardImagesTotalQuery(board_id);
const { data: totalAssets } = useGetBoardAssetsTotalQuery(board_id);
const currentViewTotal = useMemo(
() => (galleryView === 'images' ? totalImages : totalAssets),
[galleryView, totalAssets, totalImages]
);
return { totalImages, totalAssets, currentViewTotal };
};

View File

@ -0,0 +1,12 @@
import { REFINER_BASE_MODELS } from 'services/api/constants';
import { useGetMainModelsQuery } from 'services/api/endpoints/models';
export const useIsRefinerAvailable = () => {
const { isRefinerAvailable } = useGetMainModelsQuery(REFINER_BASE_MODELS, {
selectFromResult: ({ data }) => ({
isRefinerAvailable: data ? data.ids.length > 0 : false,
}),
});
return isRefinerAvailable;
};

View File

@ -8,133 +8,16 @@ import {
} from '@reduxjs/toolkit/query/react';
import { $authToken, $baseUrl } from 'services/api/client';
export type { AddInvocation } from './models/AddInvocation';
export type { BoardChanges } from './models/BoardChanges';
export type { BoardDTO } from './models/BoardDTO';
export type { Body_create_board_image } from './models/Body_create_board_image';
export type { Body_remove_board_image } from './models/Body_remove_board_image';
export type { Body_upload_image } from './models/Body_upload_image';
export type { CannyImageProcessorInvocation } from './models/CannyImageProcessorInvocation';
export type { CkptModelInfo } from './models/CkptModelInfo';
export type { ClipField } from './models/ClipField';
export type { CollectInvocation } from './models/CollectInvocation';
export type { CollectInvocationOutput } from './models/CollectInvocationOutput';
export type { ColorField } from './models/ColorField';
export type { CompelInvocation } from './models/CompelInvocation';
export type { CompelOutput } from './models/CompelOutput';
export type { ConditioningField } from './models/ConditioningField';
export type { ContentShuffleImageProcessorInvocation } from './models/ContentShuffleImageProcessorInvocation';
export type { ControlField } from './models/ControlField';
export type { ControlNetInvocation } from './models/ControlNetInvocation';
export type { ControlNetModelConfig } from './models/ControlNetModelConfig';
export type { ControlOutput } from './models/ControlOutput';
export type { CreateModelRequest } from './models/CreateModelRequest';
export type { CvInpaintInvocation } from './models/CvInpaintInvocation';
export type { DiffusersModelInfo } from './models/DiffusersModelInfo';
export type { DivideInvocation } from './models/DivideInvocation';
export type { DynamicPromptInvocation } from './models/DynamicPromptInvocation';
export type { Edge } from './models/Edge';
export type { EdgeConnection } from './models/EdgeConnection';
export type { FloatCollectionOutput } from './models/FloatCollectionOutput';
export type { FloatLinearRangeInvocation } from './models/FloatLinearRangeInvocation';
export type { FloatOutput } from './models/FloatOutput';
export type { Graph } from './models/Graph';
export type { GraphExecutionState } from './models/GraphExecutionState';
export type { GraphInvocation } from './models/GraphInvocation';
export type { GraphInvocationOutput } from './models/GraphInvocationOutput';
export type { HTTPValidationError } from './models/HTTPValidationError';
export type { ImageBlurInvocation } from './models/ImageBlurInvocation';
export type { ImageChannelInvocation } from './models/ImageChannelInvocation';
export type { ImageConvertInvocation } from './models/ImageConvertInvocation';
export type { ImageCropInvocation } from './models/ImageCropInvocation';
export type { ImageDTO } from './models/ImageDTO';
export type { ImageField } from './models/ImageField';
export type { ImageInverseLerpInvocation } from './models/ImageInverseLerpInvocation';
export type { ImageLerpInvocation } from './models/ImageLerpInvocation';
export type { ImageMetadata } from './models/ImageMetadata';
export type { ImageMultiplyInvocation } from './models/ImageMultiplyInvocation';
export type { ImageOutput } from './models/ImageOutput';
export type { ImagePasteInvocation } from './models/ImagePasteInvocation';
export type { ImageProcessorInvocation } from './models/ImageProcessorInvocation';
export type { ImageRecordChanges } from './models/ImageRecordChanges';
export type { ImageResizeInvocation } from './models/ImageResizeInvocation';
export type { ImageScaleInvocation } from './models/ImageScaleInvocation';
export type { ImageToLatentsInvocation } from './models/ImageToLatentsInvocation';
export type { ImageUrlsDTO } from './models/ImageUrlsDTO';
export type { InfillColorInvocation } from './models/InfillColorInvocation';
export type { InfillPatchMatchInvocation } from './models/InfillPatchMatchInvocation';
export type { InfillTileInvocation } from './models/InfillTileInvocation';
export type { InpaintInvocation } from './models/InpaintInvocation';
export type { IntCollectionOutput } from './models/IntCollectionOutput';
export type { IntOutput } from './models/IntOutput';
export type { IterateInvocation } from './models/IterateInvocation';
export type { IterateInvocationOutput } from './models/IterateInvocationOutput';
export type { LatentsField } from './models/LatentsField';
export type { LatentsOutput } from './models/LatentsOutput';
export type { LatentsToImageInvocation } from './models/LatentsToImageInvocation';
export type { LatentsToLatentsInvocation } from './models/LatentsToLatentsInvocation';
export type { LineartAnimeImageProcessorInvocation } from './models/LineartAnimeImageProcessorInvocation';
export type { LineartImageProcessorInvocation } from './models/LineartImageProcessorInvocation';
export type { LoadImageInvocation } from './models/LoadImageInvocation';
export type { LoraInfo } from './models/LoraInfo';
export type { LoraLoaderInvocation } from './models/LoraLoaderInvocation';
export type { LoraLoaderOutput } from './models/LoraLoaderOutput';
export type { MaskFromAlphaInvocation } from './models/MaskFromAlphaInvocation';
export type { MaskOutput } from './models/MaskOutput';
export type { MediapipeFaceProcessorInvocation } from './models/MediapipeFaceProcessorInvocation';
export type { MidasDepthImageProcessorInvocation } from './models/MidasDepthImageProcessorInvocation';
export type { MlsdImageProcessorInvocation } from './models/MlsdImageProcessorInvocation';
export type { ModelInfo } from './models/ModelInfo';
export type { ModelLoaderOutput } from './models/ModelLoaderOutput';
export type { ModelsList } from './models/ModelsList';
export type { ModelType } from './models/ModelType';
export type { MultiplyInvocation } from './models/MultiplyInvocation';
export type { NoiseInvocation } from './models/NoiseInvocation';
export type { NoiseOutput } from './models/NoiseOutput';
export type { NormalbaeImageProcessorInvocation } from './models/NormalbaeImageProcessorInvocation';
export type { OffsetPaginatedResults_BoardDTO_ } from './models/OffsetPaginatedResults_BoardDTO_';
export type { OffsetPaginatedResults_ImageDTO_ } from './models/OffsetPaginatedResults_ImageDTO_';
export type { ONNXLatentsToImageInvocation } from './models/ONNXLatentsToImageInvocation';
export type { ONNXModelLoaderOutput } from './models/ONNXModelLoaderOutput';
export type { ONNXPromptInvocation } from './models/ONNXPromptInvocation';
export type { ONNXSD1ModelLoaderInvocation } from './models/ONNXSD1ModelLoaderInvocation';
export type { ONNXStableDiffusion1ModelConfig } from './models/ONNXStableDiffusion1ModelConfig';
export type { ONNXStableDiffusion2ModelConfig } from './models/ONNXStableDiffusion2ModelConfig';
export type { ONNXTextToLatentsInvocation } from './models/ONNXTextToLatentsInvocation';
export type { OpenposeImageProcessorInvocation } from './models/OpenposeImageProcessorInvocation';
export type { PaginatedResults_GraphExecutionState_ } from './models/PaginatedResults_GraphExecutionState_';
export type { ParamFloatInvocation } from './models/ParamFloatInvocation';
export type { ParamIntInvocation } from './models/ParamIntInvocation';
export type { PidiImageProcessorInvocation } from './models/PidiImageProcessorInvocation';
export type { PipelineModelField } from './models/PipelineModelField';
export type { PipelineModelLoaderInvocation } from './models/PipelineModelLoaderInvocation';
export type { PromptCollectionOutput } from './models/PromptCollectionOutput';
export type { PromptOutput } from './models/PromptOutput';
export type { RandomIntInvocation } from './models/RandomIntInvocation';
export type { RandomRangeInvocation } from './models/RandomRangeInvocation';
export type { RangeInvocation } from './models/RangeInvocation';
export type { RangeOfSizeInvocation } from './models/RangeOfSizeInvocation';
export type { ResizeLatentsInvocation } from './models/ResizeLatentsInvocation';
export type { RestoreFaceInvocation } from './models/RestoreFaceInvocation';
export type { ScaleLatentsInvocation } from './models/ScaleLatentsInvocation';
export type { ShowImageInvocation } from './models/ShowImageInvocation';
export type { StableDiffusion1ModelCheckpointConfig } from './models/StableDiffusion1ModelCheckpointConfig';
export type { StableDiffusion1ModelDiffusersConfig } from './models/StableDiffusion1ModelDiffusersConfig';
export type { StableDiffusion2ModelCheckpointConfig } from './models/StableDiffusion2ModelCheckpointConfig';
export type { StableDiffusion2ModelDiffusersConfig } from './models/StableDiffusion2ModelDiffusersConfig';
export type { StepParamEasingInvocation } from './models/StepParamEasingInvocation';
export type { SubModelType } from './models/SubModelType';
export type { SubtractInvocation } from './models/SubtractInvocation';
export type { TextToLatentsInvocation } from './models/TextToLatentsInvocation';
export type { TextualInversionModelConfig } from './models/TextualInversionModelConfig';
export type { UNetField } from './models/UNetField';
export type { UpscaleInvocation } from './models/UpscaleInvocation';
export type { VaeField } from './models/VaeField';
export type { VaeModelConfig } from './models/VaeModelConfig';
export type { VaeRepo } from './models/VaeRepo';
export type { ValidationError } from './models/ValidationError';
export type { ZoeDepthImageProcessorInvocation } from './models/ZoeDepthImageProcessorInvocation';
export const tagTypes = ['Board', 'Image', 'ImageMetadata', 'Model'];
export const tagTypes = [
'Board',
'BoardImagesTotal',
'BoardAssetsTotal',
'Image',
'ImageNameList',
'ImageList',
'ImageMetadata',
'Model',
];
export type ApiFullTagDescription = FullTagDescription<
(typeof tagTypes)[number]
>;

View File

@ -1,36 +0,0 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { ImageField } from './ImageField';
/**
* Applies HED edge detection to image
*/
export type HedImageProcessorInvocation = {
/**
* The id of this node. Must be unique among all nodes.
*/
id: string;
/**
* Whether or not this node is an intermediate node.
*/
is_intermediate?: boolean;
type?: 'hed_image_processor';
/**
* The image to process
*/
image?: ImageField;
/**
* The pixel resolution for detection
*/
detect_resolution?: number;
/**
* The pixel resolution for the output image
*/
image_resolution?: number;
/**
* Whether to use scribble mode
*/
scribble?: boolean;
};

View File

@ -126,7 +126,7 @@ export type paths = {
* @description Call after making changes to models.yaml, autoimport directories or models directory to synchronize
* in-memory data structures with disk data structures.
*/
get: operations["sync_to_config"];
post: operations["sync_to_config"];
};
"/api/v1/models/merge/{base_model}": {
/**
@ -164,6 +164,13 @@ export type paths = {
*/
patch: operations["update_image"];
};
"/api/v1/images/clear-intermediates": {
/**
* Clear Intermediates
* @description Clears all intermediates
*/
post: operations["clear_intermediates"];
};
"/api/v1/images/{image_name}/metadata": {
/**
* Get Image Metadata
@ -221,6 +228,13 @@ export type paths = {
*/
patch: operations["update_board"];
};
"/api/v1/boards/{board_id}/image_names": {
/**
* List All Board Image Names
* @description Gets a list of images for a board
*/
get: operations["list_all_board_image_names"];
};
"/api/v1/board_images/": {
/**
* Create Board Image
@ -233,13 +247,6 @@ export type paths = {
*/
delete: operations["remove_board_image"];
};
"/api/v1/board_images/{board_id}": {
/**
* List Board Images
* @description Gets a list of images for a board
*/
get: operations["list_board_images"];
};
"/api/v1/app/version": {
/** Get Version */
get: operations["app_version"];
@ -248,6 +255,18 @@ export type paths = {
/** Get Config */
get: operations["get_config"];
};
"/api/v1/app/logging": {
/**
* Get Log Level
* @description Returns the log level
*/
get: operations["get_log_level"];
/**
* Set Log Level
* @description Sets the log verbosity level
*/
post: operations["set_log_level"];
};
};
export type webhooks = Record<string, never>;
@ -299,6 +318,21 @@ export type components = {
* @description List of available infill methods
*/
infill_methods: (string)[];
/**
* Upscaling Methods
* @description List of upscaling methods
*/
upscaling_methods: (components["schemas"]["Upscaler"])[];
/**
* Nsfw Methods
* @description List of NSFW checking methods
*/
nsfw_methods: (string)[];
/**
* Watermarking Methods
* @description List of invisible watermark methods
*/
watermarking_methods: (string)[];
};
/**
* AppVersion
@ -793,6 +827,13 @@ export type components = {
* @enum {string}
*/
control_mode?: "balanced" | "more_prompt" | "more_control" | "unbalanced";
/**
* Resize Mode
* @description The resize mode to use
* @default just_resize
* @enum {string}
*/
resize_mode?: "just_resize" | "crop_resize" | "fill_resize" | "just_resize_simple";
};
/**
* ControlNetInvocation
@ -852,6 +893,13 @@ export type components = {
* @enum {string}
*/
control_mode?: "balanced" | "more_prompt" | "more_control" | "unbalanced";
/**
* Resize Mode
* @description The resize mode used
* @default just_resize
* @enum {string}
*/
resize_mode?: "just_resize" | "crop_resize" | "fill_resize" | "just_resize_simple";
};
/** ControlNetModelConfig */
ControlNetModelConfig: {
@ -981,6 +1029,11 @@ export type components = {
* @description The LoRAs used for inference
*/
loras: (components["schemas"]["LoRAMetadataField"])[];
/**
* Vae
* @description The VAE used for decoding, if the main model's default was not used
*/
vae?: components["schemas"]["VAEModelField"];
/**
* Strength
* @description The strength used for latents-to-latents
@ -992,10 +1045,45 @@ export type components = {
*/
init_image?: string;
/**
* Vae
* @description The VAE used for decoding, if the main model's default was not used
* Positive Style Prompt
* @description The positive style prompt parameter
*/
vae?: components["schemas"]["VAEModelField"];
positive_style_prompt?: string;
/**
* Negative Style Prompt
* @description The negative style prompt parameter
*/
negative_style_prompt?: string;
/**
* Refiner Model
* @description The SDXL Refiner model used
*/
refiner_model?: components["schemas"]["MainModelField"];
/**
* Refiner Cfg Scale
* @description The classifier-free guidance scale parameter used for the refiner
*/
refiner_cfg_scale?: number;
/**
* Refiner Steps
* @description The number of steps used for the refiner
*/
refiner_steps?: number;
/**
* Refiner Scheduler
* @description The scheduler used for the refiner
*/
refiner_scheduler?: string;
/**
* Refiner Aesthetic Store
* @description The aesthetic score used for the refiner
*/
refiner_aesthetic_store?: number;
/**
* Refiner Start
* @description The start value used for refiner denoising
*/
refiner_start?: number;
};
/**
* CvInpaintInvocation
@ -1030,6 +1118,24 @@ export type components = {
*/
mask?: components["schemas"]["ImageField"];
};
/** DeleteBoardResult */
DeleteBoardResult: {
/**
* Board Id
* @description The id of the board that was deleted.
*/
board_id: string;
/**
* Deleted Board Images
* @description The image names of the board-images relationships that were deleted.
*/
deleted_board_images: (string)[];
/**
* Deleted Images
* @description The names of the images that were deleted.
*/
deleted_images: (string)[];
};
/**
* DivideInvocation
* @description Divides two numbers
@ -1254,11 +1360,7 @@ export type components = {
* @description The nodes in this graph
*/
nodes?: {
<<<<<<< HEAD
[key: string]: (components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["UpscaleInvocation"] | components["schemas"]["RestoreFaceInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"]) | undefined;
=======
[key: string]: (components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRawPromptInvocation"] | components["schemas"]["SDXLRefinerRawPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["ParamStringInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SDXLTextToLatentsInvocation"] | components["schemas"]["SDXLLatentsToLatentsInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"]) | undefined;
>>>>>>> main
[key: string]: (components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRawPromptInvocation"] | components["schemas"]["SDXLRefinerRawPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SDXLTextToLatentsInvocation"] | components["schemas"]["SDXLLatentsToLatentsInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["ParamStringInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"]) | undefined;
};
/**
* Edges
@ -1301,7 +1403,7 @@ export type components = {
* @description The results of node executions
*/
results: {
[key: string]: (components["schemas"]["ImageOutput"] | components["schemas"]["MaskOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["CompelOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["IntOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["IntCollectionOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["PromptOutput"] | components["schemas"]["PromptCollectionOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["CollectInvocationOutput"]) | undefined;
[key: string]: (components["schemas"]["ImageOutput"] | components["schemas"]["MaskOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["CompelOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["PromptOutput"] | components["schemas"]["PromptCollectionOutput"] | components["schemas"]["IntOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["IntCollectionOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["CollectInvocationOutput"]) | undefined;
};
/**
* Errors
@ -1848,6 +1950,39 @@ export type components = {
*/
image2?: components["schemas"]["ImageField"];
};
/**
* ImageNSFWBlurInvocation
* @description Add blur to NSFW-flagged images
*/
ImageNSFWBlurInvocation: {
/**
* Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
* Is Intermediate
* @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
* Type
* @default img_nsfw
* @enum {string}
*/
type?: "img_nsfw";
/**
* Image
* @description The image to check
*/
image?: components["schemas"]["ImageField"];
/**
* Metadata
* @description Optional core metadata to be written to the image
*/
metadata?: components["schemas"]["CoreMetadata"];
};
/**
* ImageOutput
* @description Base class for invocations that output an image
@ -2128,6 +2263,45 @@ export type components = {
*/
thumbnail_url: string;
};
/**
* ImageWatermarkInvocation
* @description Add an invisible watermark to an image
*/
ImageWatermarkInvocation: {
/**
* Id
* @description The id of this node. Must be unique among all nodes.
*/
id: string;
/**
* Is Intermediate
* @description Whether or not this node is an intermediate node.
* @default false
*/
is_intermediate?: boolean;
/**
* Type
* @default img_watermark
* @enum {string}
*/
type?: "img_watermark";
/**
* Image
* @description The image to check
*/
image?: components["schemas"]["ImageField"];
/**
* Text
* @description Watermark text
* @default InvokeAI
*/
text?: string;
/**
* Metadata
* @description Optional core metadata to be written to the image
*/
metadata?: components["schemas"]["CoreMetadata"];
};
/**
* InfillColorInvocation
* @description Infills transparent areas of an image with a solid color
@ -2557,7 +2731,7 @@ export type components = {
vae?: components["schemas"]["VaeField"];
/**
* Tiled
* @description Decode latents by overlaping tiles(less memory consumption)
* @description Decode latents by overlapping tiles(less memory consumption)
* @default false
*/
tiled?: boolean;
@ -2875,6 +3049,12 @@ export type components = {
*/
image?: components["schemas"]["ImageField"];
};
/**
* LogLevel
* @description An enumeration.
* @enum {integer}
*/
LogLevel: 0 | 10 | 20 | 30 | 40 | 50;
/** LoraInfo */
LoraInfo: {
/**
@ -3260,6 +3440,46 @@ export type components = {
* @description The VAE used for decoding, if the main model's default was not used
*/
vae?: components["schemas"]["VAEModelField"];
/**
* Positive Style Prompt
* @description The positive style prompt parameter
*/
positive_style_prompt?: string;
/**
* Negative Style Prompt
* @description The negative style prompt parameter
*/
negative_style_prompt?: string;
/**
* Refiner Model
* @description The SDXL Refiner model used
*/
refiner_model?: components["schemas"]["MainModelField"];
/**
* Refiner Cfg Scale
* @description The classifier-free guidance scale parameter used for the refiner
*/
refiner_cfg_scale?: number;
/**
* Refiner Steps
* @description The number of steps used for the refiner
*/
refiner_steps?: number;
/**
* Refiner Scheduler
* @description The scheduler used for the refiner
*/
refiner_scheduler?: string;
/**
* Refiner Aesthetic Store
* @description The aesthetic score used for the refiner
*/
refiner_aesthetic_store?: number;
/**
* Refiner Start
* @description The start value used for refiner denoising
*/
refiner_start?: number;
};
/**
* MetadataAccumulatorOutput
@ -5221,6 +5441,19 @@ export type components = {
*/
loras: (components["schemas"]["LoraInfo"])[];
};
/** Upscaler */
Upscaler: {
/**
* Upscaling Method
* @description Name of upscaling method
*/
upscaling_method: string;
/**
* Upscaling Models
* @description List of upscaling models for this method
*/
upscaling_models: (string)[];
};
/**
* VAEModelField
* @description Vae model field
@ -5347,6 +5580,12 @@ export type components = {
*/
image?: components["schemas"]["ImageField"];
};
/**
* StableDiffusion1ModelFormat
* @description An enumeration.
* @enum {string}
*/
StableDiffusion1ModelFormat: "checkpoint" | "diffusers";
/**
* StableDiffusion2ModelFormat
* @description An enumeration.
@ -5359,12 +5598,6 @@ export type components = {
* @enum {string}
*/
StableDiffusionXLModelFormat: "checkpoint" | "diffusers";
/**
* StableDiffusion1ModelFormat
* @description An enumeration.
* @enum {string}
*/
StableDiffusion1ModelFormat: "checkpoint" | "diffusers";
};
responses: never;
parameters: never;
@ -5475,7 +5708,7 @@ export type operations = {
};
requestBody: {
content: {
"application/json": components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRawPromptInvocation"] | components["schemas"]["SDXLRefinerRawPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["ParamStringInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SDXLTextToLatentsInvocation"] | components["schemas"]["SDXLLatentsToLatentsInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"];
"application/json": components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRawPromptInvocation"] | components["schemas"]["SDXLRefinerRawPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SDXLTextToLatentsInvocation"] | components["schemas"]["SDXLLatentsToLatentsInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["ParamStringInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"];
};
};
responses: {
@ -5512,7 +5745,7 @@ export type operations = {
};
requestBody: {
content: {
"application/json": components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRawPromptInvocation"] | components["schemas"]["SDXLRefinerRawPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["ParamStringInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SDXLTextToLatentsInvocation"] | components["schemas"]["SDXLLatentsToLatentsInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"];
"application/json": components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["SDXLRawPromptInvocation"] | components["schemas"]["SDXLRefinerRawPromptInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SDXLTextToLatentsInvocation"] | components["schemas"]["SDXLLatentsToLatentsInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["ParamStringInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"];
};
};
responses: {
@ -5951,7 +6184,7 @@ export type operations = {
/** @description synchronization successful */
201: {
content: {
"application/json": unknown;
"application/json": boolean;
};
};
};
@ -5998,13 +6231,13 @@ export type operations = {
list_image_dtos: {
parameters: {
query?: {
/** @description The origin of images to list */
/** @description The origin of images to list. */
image_origin?: components["schemas"]["ResourceOrigin"];
/** @description The categories of image to include */
/** @description The categories of image to include. */
categories?: (components["schemas"]["ImageCategory"])[];
/** @description Whether to list intermediate images */
/** @description Whether to list intermediate images. */
is_intermediate?: boolean;
/** @description The board id to filter by */
/** @description The board id to filter by. Use 'none' to find images without a board. */
board_id?: string;
/** @description The page offset */
offset?: number;
@ -6038,8 +6271,12 @@ export type operations = {
image_category: components["schemas"]["ImageCategory"];
/** @description Whether this is an intermediate image */
is_intermediate: boolean;
/** @description The board to add this image to, if any */
board_id?: string;
/** @description The session ID associated with this upload, if any */
session_id?: string;
/** @description Whether to crop the image */
crop_visible?: boolean;
};
};
requestBody: {
@ -6147,6 +6384,20 @@ export type operations = {
};
};
};
/**
* Clear Intermediates
* @description Clears all intermediates
*/
clear_intermediates: {
responses: {
/** @description Successful Response */
200: {
content: {
"application/json": unknown;
};
};
};
};
/**
* Get Image Metadata
* @description Gets an image's metadata
@ -6356,7 +6607,7 @@ export type operations = {
/** @description Successful Response */
200: {
content: {
"application/json": unknown;
"application/json": components["schemas"]["DeleteBoardResult"];
};
};
/** @description Validation Error */
@ -6398,6 +6649,32 @@ export type operations = {
};
};
};
/**
* List All Board Image Names
* @description Gets a list of images for a board
*/
list_all_board_image_names: {
parameters: {
path: {
/** @description The id of the board */
board_id: string;
};
};
responses: {
/** @description Successful Response */
200: {
content: {
"application/json": (string)[];
};
};
/** @description Validation Error */
422: {
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
/**
* Create Board Image
* @description Creates a board_image
@ -6448,38 +6725,6 @@ export type operations = {
};
};
};
/**
* List Board Images
* @description Gets a list of images for a board
*/
list_board_images: {
parameters: {
query?: {
/** @description The page offset */
offset?: number;
/** @description The number of boards per page */
limit?: number;
};
path: {
/** @description The id of the board */
board_id: string;
};
};
responses: {
/** @description Successful Response */
200: {
content: {
"application/json": components["schemas"]["OffsetPaginatedResults_ImageDTO_"];
};
};
/** @description Validation Error */
422: {
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
/** Get Version */
app_version: {
responses: {
@ -6502,4 +6747,43 @@ export type operations = {
};
};
};
/**
* Get Log Level
* @description Returns the log level
*/
get_log_level: {
responses: {
/** @description The operation was successful */
200: {
content: {
"application/json": components["schemas"]["LogLevel"];
};
};
};
};
/**
* Set Log Level
* @description Sets the log verbosity level
*/
set_log_level: {
requestBody: {
content: {
"application/json": components["schemas"]["LogLevel"];
};
};
responses: {
/** @description The operation was successful */
200: {
content: {
"application/json": components["schemas"]["LogLevel"];
};
};
/** @description Validation Error */
422: {
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
};

View File

@ -1,330 +0,0 @@
import { createAppAsyncThunk } from 'app/store/storeUtils';
import { selectFilteredImages } from 'features/gallery/store/gallerySelectors';
import {
ASSETS_CATEGORIES,
IMAGE_CATEGORIES,
} from 'features/gallery/store/gallerySlice';
import { size } from 'lodash-es';
import queryString from 'query-string';
import { $client } from 'services/api/client';
import { paths } from 'services/api/schema';
type GetImageUrlsArg =
paths['/api/v1/images/{image_name}/urls']['get']['parameters']['path'];
type GetImageUrlsResponse =
paths['/api/v1/images/{image_name}/urls']['get']['responses']['200']['content']['application/json'];
type GetImageUrlsThunkConfig = {
rejectValue: {
arg: GetImageUrlsArg;
error: unknown;
};
};
/**
* Thunk to get image URLs
*/
export const imageUrlsReceived = createAppAsyncThunk<
GetImageUrlsResponse,
GetImageUrlsArg,
GetImageUrlsThunkConfig
>('thunkApi/imageUrlsReceived', async (arg, { rejectWithValue }) => {
const { image_name } = arg;
const { get } = $client.get();
const { data, error, response } = await get(
'/api/v1/images/{image_name}/urls',
{
params: {
path: {
image_name,
},
},
}
);
if (error) {
return rejectWithValue({ arg, error });
}
return data;
});
type GetImageMetadataArg =
paths['/api/v1/images/{image_name}']['get']['parameters']['path'];
type GetImageMetadataResponse =
paths['/api/v1/images/{image_name}']['get']['responses']['200']['content']['application/json'];
type GetImageMetadataThunkConfig = {
rejectValue: {
arg: GetImageMetadataArg;
error: unknown;
};
};
export const imageDTOReceived = createAppAsyncThunk<
GetImageMetadataResponse,
GetImageMetadataArg,
GetImageMetadataThunkConfig
>('thunkApi/imageMetadataReceived', async (arg, { rejectWithValue }) => {
const { image_name } = arg;
const { get } = $client.get();
const { data, error, response } = await get('/api/v1/images/{image_name}', {
params: {
path: { image_name },
},
});
if (error) {
return rejectWithValue({ arg, error });
}
return data;
});
type ControlNetAction = {
type: 'SET_CONTROLNET_IMAGE';
controlNetId: string;
};
type InitialImageAction = {
type: 'SET_INITIAL_IMAGE';
};
type NodesAction = {
type: 'SET_NODES_IMAGE';
nodeId: string;
fieldName: string;
};
type CanvasInitialImageAction = {
type: 'SET_CANVAS_INITIAL_IMAGE';
};
type CanvasMergedAction = {
type: 'TOAST_CANVAS_MERGED';
};
type CanvasSavedToGalleryAction = {
type: 'TOAST_CANVAS_SAVED_TO_GALLERY';
};
type UploadedToastAction = {
type: 'TOAST_UPLOADED';
};
type AddToBatchAction = {
type: 'ADD_TO_BATCH';
};
export type PostUploadAction =
| ControlNetAction
| InitialImageAction
| NodesAction
| CanvasInitialImageAction
| CanvasMergedAction
| CanvasSavedToGalleryAction
| UploadedToastAction
| AddToBatchAction;
type UploadImageArg =
paths['/api/v1/images/']['post']['parameters']['query'] & {
file: File;
postUploadAction?: PostUploadAction;
};
type UploadImageResponse =
paths['/api/v1/images/']['post']['responses']['201']['content']['application/json'];
type UploadImageThunkConfig = {
rejectValue: {
arg: UploadImageArg;
error: unknown;
};
};
/**
* `ImagesService.uploadImage()` thunk
*/
export const imageUploaded = createAppAsyncThunk<
UploadImageResponse,
UploadImageArg,
UploadImageThunkConfig
>('thunkApi/imageUploaded', async (arg, { rejectWithValue }) => {
const {
postUploadAction,
file,
image_category,
is_intermediate,
session_id,
} = arg;
const { post } = $client.get();
const { data, error, response } = await post('/api/v1/images/', {
params: {
query: {
image_category,
is_intermediate,
session_id,
},
},
body: { file },
bodySerializer: (body) => {
const formData = new FormData();
formData.append('file', body.file);
return formData;
},
});
if (error) {
return rejectWithValue({ arg, error });
}
return data;
});
type DeleteImageArg =
paths['/api/v1/images/{image_name}']['delete']['parameters']['path'];
type DeleteImageResponse =
paths['/api/v1/images/{image_name}']['delete']['responses']['200']['content']['application/json'];
type DeleteImageThunkConfig = {
rejectValue: {
arg: DeleteImageArg;
error: unknown;
};
};
/**
* `ImagesService.deleteImage()` thunk
*/
export const imageDeleted = createAppAsyncThunk<
DeleteImageResponse,
DeleteImageArg,
DeleteImageThunkConfig
>('thunkApi/imageDeleted', async (arg, { rejectWithValue }) => {
const { image_name } = arg;
const { del } = $client.get();
const { data, error, response } = await del('/api/v1/images/{image_name}', {
params: {
path: {
image_name,
},
},
});
if (error) {
return rejectWithValue({ arg, error });
}
});
type UpdateImageArg =
paths['/api/v1/images/{image_name}']['patch']['requestBody']['content']['application/json'] &
paths['/api/v1/images/{image_name}']['patch']['parameters']['path'];
type UpdateImageResponse =
paths['/api/v1/images/{image_name}']['patch']['responses']['200']['content']['application/json'];
type UpdateImageThunkConfig = {
rejectValue: {
arg: UpdateImageArg;
error: unknown;
};
};
/**
* `ImagesService.updateImage()` thunk
*/
export const imageUpdated = createAppAsyncThunk<
UpdateImageResponse,
UpdateImageArg,
UpdateImageThunkConfig
>('thunkApi/imageUpdated', async (arg, { rejectWithValue }) => {
const { image_name, image_category, is_intermediate, session_id } = arg;
const { patch } = $client.get();
const { data, error, response } = await patch('/api/v1/images/{image_name}', {
params: {
path: {
image_name,
},
},
body: {
image_category,
is_intermediate,
session_id,
},
});
if (error) {
return rejectWithValue({ arg, error });
}
return data;
});
export const IMAGES_PER_PAGE = 20;
const DEFAULT_IMAGES_LISTED_ARG = {
limit: IMAGES_PER_PAGE,
};
type ListImagesArg = NonNullable<
paths['/api/v1/images/']['get']['parameters']['query']
>;
type ListImagesResponse =
paths['/api/v1/images/']['get']['responses']['200']['content']['application/json'];
type ListImagesThunkConfig = {
rejectValue: {
arg: ListImagesArg;
error: unknown;
};
};
/**
* `ImagesService.listImagesWithMetadata()` thunk
*/
export const receivedPageOfImages = createAppAsyncThunk<
ListImagesResponse,
ListImagesArg,
ListImagesThunkConfig
>(
'thunkApi/receivedPageOfImages',
async (arg, { getState, rejectWithValue }) => {
const { get } = $client.get();
const state = getState();
const images = selectFilteredImages(state);
const categories =
state.gallery.galleryView === 'images'
? IMAGE_CATEGORIES
: ASSETS_CATEGORIES;
let query: ListImagesArg = {};
if (size(arg)) {
query = {
...DEFAULT_IMAGES_LISTED_ARG,
offset: images.length,
...arg,
};
} else {
query = {
...DEFAULT_IMAGES_LISTED_ARG,
categories,
offset: images.length,
};
}
const { data, error, response } = await get('/api/v1/images/', {
params: {
query,
},
querySerializer: (q) => queryString.stringify(q, { arrayFormat: 'none' }),
});
if (error) {
return rejectWithValue({ arg, error });
}
return data;
}
);

View File

@ -1,7 +1,5 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
import { log } from 'app/logging/useLogger';
const schemaLog = log.child({ namespace: 'schema' });
import { logger } from 'app/logging/logger';
function getCircularReplacer() {
const ancestors: Record<string, any>[] = [];
@ -26,11 +24,12 @@ function getCircularReplacer() {
export const receivedOpenAPISchema = createAsyncThunk(
'nodes/receivedOpenAPISchema',
async (_, { dispatch, rejectWithValue }) => {
const log = logger('system');
try {
const response = await fetch(`openapi.json`);
const openAPISchema = await response.json();
schemaLog.info({ openAPISchema }, 'Received OpenAPI schema');
log.info({ openAPISchema }, 'Received OpenAPI schema');
const schemaJSON = JSON.parse(
JSON.stringify(openAPISchema, getCircularReplacer())

View File

@ -1,13 +1,9 @@
import { createAppAsyncThunk } from 'app/store/storeUtils';
import { log } from 'app/logging/useLogger';
import { createAsyncThunk, isAnyOf } from '@reduxjs/toolkit';
import { isObject } from 'lodash-es';
import { isAnyOf } from '@reduxjs/toolkit';
import { paths } from 'services/api/schema';
import { $client } from 'services/api/client';
import { paths } from 'services/api/schema';
import { O } from 'ts-toolbelt';
const sessionLog = log.child({ namespace: 'session' });
type CreateSessionArg = {
graph: NonNullable<
paths['/api/v1/sessions/']['post']['requestBody']
@ -22,13 +18,13 @@ type CreateSessionResponse = O.Required<
>;
type CreateSessionThunkConfig = {
rejectValue: { arg: CreateSessionArg; error: unknown };
rejectValue: { arg: CreateSessionArg; status: number; error: unknown };
};
/**
* `SessionsService.createSession()` thunk
*/
export const sessionCreated = createAppAsyncThunk<
export const sessionCreated = createAsyncThunk<
CreateSessionResponse,
CreateSessionArg,
CreateSessionThunkConfig
@ -40,7 +36,7 @@ export const sessionCreated = createAppAsyncThunk<
});
if (error) {
return rejectWithValue({ arg, error });
return rejectWithValue({ arg, status: response.status, error });
}
return data;
@ -57,6 +53,7 @@ type InvokedSessionThunkConfig = {
rejectValue: {
arg: InvokedSessionArg;
error: unknown;
status: number;
};
};
@ -66,7 +63,7 @@ const isErrorWithStatus = (error: unknown): error is { status: number } =>
/**
* `SessionsService.invokeSession()` thunk
*/
export const sessionInvoked = createAppAsyncThunk<
export const sessionInvoked = createAsyncThunk<
InvokedSessionResponse,
InvokedSessionArg,
InvokedSessionThunkConfig
@ -82,9 +79,13 @@ export const sessionInvoked = createAppAsyncThunk<
if (error) {
if (isErrorWithStatus(error) && error.status === 403) {
return rejectWithValue({ arg, error: (error as any).body.detail });
return rejectWithValue({
arg,
status: response.status,
error: (error as any).body.detail,
});
}
return rejectWithValue({ arg, error });
return rejectWithValue({ arg, status: response.status, error });
}
});
@ -104,7 +105,7 @@ type CancelSessionThunkConfig = {
/**
* `SessionsService.cancelSession()` thunk
*/
export const sessionCanceled = createAppAsyncThunk<
export const sessionCanceled = createAsyncThunk<
CancelSessionResponse,
CancelSessionArg,
CancelSessionThunkConfig
@ -144,7 +145,7 @@ type ListSessionsThunkConfig = {
/**
* `SessionsService.listSessions()` thunk
*/
export const listedSessions = createAppAsyncThunk<
export const listedSessions = createAsyncThunk<
ListSessionsResponse,
ListSessionsArg,
ListSessionsThunkConfig

View File

@ -1,3 +1,4 @@
import { UseToastOptions } from '@chakra-ui/react';
import { O } from 'ts-toolbelt';
import { components } from './schema';
@ -140,6 +141,12 @@ export type ESRGANInvocation = TypeReq<
export type DivideInvocation = TypeReq<
components['schemas']['DivideInvocation']
>;
export type ImageNSFWBlurInvocation = TypeReq<
components['schemas']['ImageNSFWBlurInvocation']
>;
export type ImageWatermarkInvocation = TypeReq<
components['schemas']['ImageWatermarkInvocation']
>;
// ControlNet Nodes
export type ControlNetInvocation = TypeReq<
@ -193,3 +200,41 @@ export type CollectInvocationOutput =
export type LatentsOutput = components['schemas']['LatentsOutput'];
export type GraphInvocationOutput =
components['schemas']['GraphInvocationOutput'];
// Post-image upload actions, controls workflows when images are uploaded
export type ControlNetAction = {
type: 'SET_CONTROLNET_IMAGE';
controlNetId: string;
};
export type InitialImageAction = {
type: 'SET_INITIAL_IMAGE';
};
export type NodesAction = {
type: 'SET_NODES_IMAGE';
nodeId: string;
fieldName: string;
};
export type CanvasInitialImageAction = {
type: 'SET_CANVAS_INITIAL_IMAGE';
};
export type ToastAction = {
type: 'TOAST';
toastOptions?: UseToastOptions;
};
export type AddToBatchAction = {
type: 'ADD_TO_BATCH';
};
export type PostUploadAction =
| ControlNetAction
| InitialImageAction
| NodesAction
| CanvasInitialImageAction
| ToastAction
| AddToBatchAction;

View File

@ -4,16 +4,13 @@ import {
GraphExecutionStateCompleteEvent,
InvocationCompleteEvent,
InvocationErrorEvent,
InvocationRetrievalErrorEvent,
InvocationStartedEvent,
ModelLoadCompletedEvent,
ModelLoadStartedEvent,
SessionRetrievalErrorEvent,
} from 'services/events/types';
// Common socket action payload data
type BaseSocketPayload = {
timestamp: string;
};
// Create actions for each socket
// Middleware and redux can then respond to them as needed
@ -22,30 +19,24 @@ type BaseSocketPayload = {
*
* Do not use. Only for use in middleware.
*/
export const socketConnected = createAction<BaseSocketPayload>(
'socket/socketConnected'
);
export const socketConnected = createAction('socket/socketConnected');
/**
* App-level Socket.IO Connected
*/
export const appSocketConnected = createAction<BaseSocketPayload>(
'socket/appSocketConnected'
);
export const appSocketConnected = createAction('socket/appSocketConnected');
/**
* Socket.IO Disconnect
*
* Do not use. Only for use in middleware.
*/
export const socketDisconnected = createAction<BaseSocketPayload>(
'socket/socketDisconnected'
);
export const socketDisconnected = createAction('socket/socketDisconnected');
/**
* App-level Socket.IO Disconnected
*/
export const appSocketDisconnected = createAction<BaseSocketPayload>(
export const appSocketDisconnected = createAction(
'socket/appSocketDisconnected'
);
@ -54,145 +45,173 @@ export const appSocketDisconnected = createAction<BaseSocketPayload>(
*
* Do not use. Only for use in middleware.
*/
export const socketSubscribed = createAction<
BaseSocketPayload & { sessionId: string; boardId: string | undefined }
>('socket/socketSubscribed');
export const socketSubscribed = createAction<{
sessionId: string;
}>('socket/socketSubscribed');
/**
* App-level Socket.IO Subscribed
*/
export const appSocketSubscribed = createAction<
BaseSocketPayload & { sessionId: string; boardId: string | undefined }
>('socket/appSocketSubscribed');
export const appSocketSubscribed = createAction<{
sessionId: string;
}>('socket/appSocketSubscribed');
/**
* Socket.IO Unsubscribed
*
* Do not use. Only for use in middleware.
*/
export const socketUnsubscribed = createAction<
BaseSocketPayload & { sessionId: string }
>('socket/socketUnsubscribed');
export const socketUnsubscribed = createAction<{ sessionId: string }>(
'socket/socketUnsubscribed'
);
/**
* App-level Socket.IO Unsubscribed
*/
export const appSocketUnsubscribed = createAction<
BaseSocketPayload & { sessionId: string }
>('socket/appSocketUnsubscribed');
export const appSocketUnsubscribed = createAction<{ sessionId: string }>(
'socket/appSocketUnsubscribed'
);
/**
* Socket.IO Invocation Started
*
* Do not use. Only for use in middleware.
*/
export const socketInvocationStarted = createAction<
BaseSocketPayload & { data: InvocationStartedEvent }
>('socket/socketInvocationStarted');
export const socketInvocationStarted = createAction<{
data: InvocationStartedEvent;
}>('socket/socketInvocationStarted');
/**
* App-level Socket.IO Invocation Started
*/
export const appSocketInvocationStarted = createAction<
BaseSocketPayload & { data: InvocationStartedEvent }
>('socket/appSocketInvocationStarted');
export const appSocketInvocationStarted = createAction<{
data: InvocationStartedEvent;
}>('socket/appSocketInvocationStarted');
/**
* Socket.IO Invocation Complete
*
* Do not use. Only for use in middleware.
*/
export const socketInvocationComplete = createAction<
BaseSocketPayload & {
data: InvocationCompleteEvent;
}
>('socket/socketInvocationComplete');
export const socketInvocationComplete = createAction<{
data: InvocationCompleteEvent;
}>('socket/socketInvocationComplete');
/**
* App-level Socket.IO Invocation Complete
*/
export const appSocketInvocationComplete = createAction<
BaseSocketPayload & {
data: InvocationCompleteEvent;
}
>('socket/appSocketInvocationComplete');
export const appSocketInvocationComplete = createAction<{
data: InvocationCompleteEvent;
}>('socket/appSocketInvocationComplete');
/**
* Socket.IO Invocation Error
*
* Do not use. Only for use in middleware.
*/
export const socketInvocationError = createAction<
BaseSocketPayload & { data: InvocationErrorEvent }
>('socket/socketInvocationError');
export const socketInvocationError = createAction<{
data: InvocationErrorEvent;
}>('socket/socketInvocationError');
/**
* App-level Socket.IO Invocation Error
*/
export const appSocketInvocationError = createAction<
BaseSocketPayload & { data: InvocationErrorEvent }
>('socket/appSocketInvocationError');
export const appSocketInvocationError = createAction<{
data: InvocationErrorEvent;
}>('socket/appSocketInvocationError');
/**
* Socket.IO Graph Execution State Complete
*
* Do not use. Only for use in middleware.
*/
export const socketGraphExecutionStateComplete = createAction<
BaseSocketPayload & { data: GraphExecutionStateCompleteEvent }
>('socket/socketGraphExecutionStateComplete');
export const socketGraphExecutionStateComplete = createAction<{
data: GraphExecutionStateCompleteEvent;
}>('socket/socketGraphExecutionStateComplete');
/**
* App-level Socket.IO Graph Execution State Complete
*/
export const appSocketGraphExecutionStateComplete = createAction<
BaseSocketPayload & { data: GraphExecutionStateCompleteEvent }
>('socket/appSocketGraphExecutionStateComplete');
export const appSocketGraphExecutionStateComplete = createAction<{
data: GraphExecutionStateCompleteEvent;
}>('socket/appSocketGraphExecutionStateComplete');
/**
* Socket.IO Generator Progress
*
* Do not use. Only for use in middleware.
*/
export const socketGeneratorProgress = createAction<
BaseSocketPayload & { data: GeneratorProgressEvent }
>('socket/socketGeneratorProgress');
export const socketGeneratorProgress = createAction<{
data: GeneratorProgressEvent;
}>('socket/socketGeneratorProgress');
/**
* App-level Socket.IO Generator Progress
*/
export const appSocketGeneratorProgress = createAction<
BaseSocketPayload & { data: GeneratorProgressEvent }
>('socket/appSocketGeneratorProgress');
export const appSocketGeneratorProgress = createAction<{
data: GeneratorProgressEvent;
}>('socket/appSocketGeneratorProgress');
/**
* Socket.IO Model Load Started
*
* Do not use. Only for use in middleware.
*/
export const socketModelLoadStarted = createAction<
BaseSocketPayload & { data: ModelLoadStartedEvent }
>('socket/socketModelLoadStarted');
export const socketModelLoadStarted = createAction<{
data: ModelLoadStartedEvent;
}>('socket/socketModelLoadStarted');
/**
* App-level Model Load Started
*/
export const appSocketModelLoadStarted = createAction<
BaseSocketPayload & { data: ModelLoadStartedEvent }
>('socket/appSocketModelLoadStarted');
export const appSocketModelLoadStarted = createAction<{
data: ModelLoadStartedEvent;
}>('socket/appSocketModelLoadStarted');
/**
* Socket.IO Model Load Started
*
* Do not use. Only for use in middleware.
*/
export const socketModelLoadCompleted = createAction<
BaseSocketPayload & { data: ModelLoadCompletedEvent }
>('socket/socketModelLoadCompleted');
export const socketModelLoadCompleted = createAction<{
data: ModelLoadCompletedEvent;
}>('socket/socketModelLoadCompleted');
/**
* App-level Model Load Completed
*/
export const appSocketModelLoadCompleted = createAction<
BaseSocketPayload & { data: ModelLoadCompletedEvent }
>('socket/appSocketModelLoadCompleted');
export const appSocketModelLoadCompleted = createAction<{
data: ModelLoadCompletedEvent;
}>('socket/appSocketModelLoadCompleted');
/**
* Socket.IO Session Retrieval Error
*
* Do not use. Only for use in middleware.
*/
export const socketSessionRetrievalError = createAction<{
data: SessionRetrievalErrorEvent;
}>('socket/socketSessionRetrievalError');
/**
* App-level Session Retrieval Error
*/
export const appSocketSessionRetrievalError = createAction<{
data: SessionRetrievalErrorEvent;
}>('socket/appSocketSessionRetrievalError');
/**
* Socket.IO Invocation Retrieval Error
*
* Do not use. Only for use in middleware.
*/
export const socketInvocationRetrievalError = createAction<{
data: InvocationRetrievalErrorEvent;
}>('socket/socketInvocationRetrievalError');
/**
* App-level Invocation Retrieval Error
*/
export const appSocketInvocationRetrievalError = createAction<{
data: InvocationRetrievalErrorEvent;
}>('socket/appSocketInvocationRetrievalError');

View File

@ -1,20 +1,14 @@
import { Middleware, MiddlewareAPI } from '@reduxjs/toolkit';
import { Socket, io } from 'socket.io-client';
import { AppThunkDispatch, RootState } from 'app/store/store';
import { getTimestamp } from 'common/util/getTimestamp';
import { $authToken, $baseUrl } from 'services/api/client';
import { sessionCreated } from 'services/api/thunks/session';
import {
ClientToServerEvents,
ServerToClientEvents,
} from 'services/events/types';
import { socketSubscribed, socketUnsubscribed } from './actions';
// import { OpenAPI } from 'services/api/types';
import { log } from 'app/logging/useLogger';
import { $authToken, $baseUrl } from 'services/api/client';
import { setEventListeners } from 'services/events/util/setEventListeners';
const socketioLog = log.child({ namespace: 'socketio' });
import { Socket, io } from 'socket.io-client';
import { socketSubscribed, socketUnsubscribed } from './actions';
export const socketMiddleware = () => {
let areListenersSet = false;
@ -58,7 +52,7 @@ export const socketMiddleware = () => {
// Set listeners for `connect` and `disconnect` events once
// Must happen in middleware to get access to `dispatch`
if (!areListenersSet) {
setEventListeners({ storeApi, socket, log: socketioLog });
setEventListeners({ storeApi, socket });
areListenersSet = true;
@ -77,7 +71,6 @@ export const socketMiddleware = () => {
dispatch(
socketUnsubscribed({
sessionId: oldSessionId,
timestamp: getTimestamp(),
})
);
}
@ -87,8 +80,6 @@ export const socketMiddleware = () => {
dispatch(
socketSubscribed({
sessionId: sessionId,
timestamp: getTimestamp(),
boardId: getState().gallery.selectedBoardId,
})
);
}

View File

@ -87,6 +87,7 @@ export type InvocationErrorEvent = {
graph_execution_state_id: string;
node: BaseNode;
source_node_id: string;
error_type: string;
error: string;
};
@ -110,6 +111,29 @@ export type GraphExecutionStateCompleteEvent = {
graph_execution_state_id: string;
};
/**
* A `session_retrieval_error` socket.io event.
*
* @example socket.on('session_retrieval_error', (data: SessionRetrievalErrorEvent) => { ... }
*/
export type SessionRetrievalErrorEvent = {
graph_execution_state_id: string;
error_type: string;
error: string;
};
/**
* A `invocation_retrieval_error` socket.io event.
*
* @example socket.on('invocation_retrieval_error', (data: InvocationRetrievalErrorEvent) => { ... }
*/
export type InvocationRetrievalErrorEvent = {
graph_execution_state_id: string;
node_id: string;
error_type: string;
error: string;
};
export type ClientEmitSubscribe = {
session: string;
};
@ -128,6 +152,8 @@ export type ServerToClientEvents = {
) => void;
model_load_started: (payload: ModelLoadStartedEvent) => void;
model_load_completed: (payload: ModelLoadCompletedEvent) => void;
session_retrieval_error: (payload: SessionRetrievalErrorEvent) => void;
invocation_retrieval_error: (payload: InvocationRetrievalErrorEvent) => void;
};
export type ClientToServerEvents = {

View File

@ -1,42 +1,42 @@
import { MiddlewareAPI } from '@reduxjs/toolkit';
import { logger } from 'app/logging/logger';
import { AppDispatch, RootState } from 'app/store/store';
import { getTimestamp } from 'common/util/getTimestamp';
import { addToast } from 'features/system/store/systemSlice';
import { makeToast } from 'features/system/util/makeToast';
import { Socket } from 'socket.io-client';
import {
socketConnected,
socketDisconnected,
socketGeneratorProgress,
socketGraphExecutionStateComplete,
socketInvocationComplete,
socketInvocationError,
socketInvocationRetrievalError,
socketInvocationStarted,
socketConnected,
socketDisconnected,
socketSubscribed,
socketModelLoadStarted,
socketModelLoadCompleted,
socketModelLoadStarted,
socketSessionRetrievalError,
socketSubscribed,
} from '../actions';
import { ClientToServerEvents, ServerToClientEvents } from '../types';
import { Logger } from 'roarr';
import { JsonObject } from 'roarr/dist/types';
import { makeToast } from '../../../app/components/Toaster';
import { addToast } from '../../../features/system/store/systemSlice';
type SetEventListenersArg = {
socket: Socket<ServerToClientEvents, ClientToServerEvents>;
storeApi: MiddlewareAPI<AppDispatch, RootState>;
log: Logger<JsonObject>;
};
export const setEventListeners = (arg: SetEventListenersArg) => {
const { socket, storeApi, log } = arg;
const { socket, storeApi } = arg;
const { dispatch, getState } = storeApi;
/**
* Connect
*/
socket.on('connect', () => {
const log = logger('socketio');
log.debug('Connected');
dispatch(socketConnected({ timestamp: getTimestamp() }));
dispatch(socketConnected());
const { sessionId } = getState().system;
@ -45,8 +45,6 @@ export const setEventListeners = (arg: SetEventListenersArg) => {
dispatch(
socketSubscribed({
sessionId,
timestamp: getTimestamp(),
boardId: getState().gallery.selectedBoardId,
})
);
}
@ -54,7 +52,9 @@ export const setEventListeners = (arg: SetEventListenersArg) => {
socket.on('connect_error', (error) => {
if (error && error.message) {
const data: string | undefined = (error as any).data;
const data: string | undefined = (
error as unknown as { data: string | undefined }
).data;
if (data === 'ERR_UNAUTHENTICATED') {
dispatch(
addToast(
@ -73,28 +73,28 @@ export const setEventListeners = (arg: SetEventListenersArg) => {
* Disconnect
*/
socket.on('disconnect', () => {
dispatch(socketDisconnected({ timestamp: getTimestamp() }));
dispatch(socketDisconnected());
});
/**
* Invocation started
*/
socket.on('invocation_started', (data) => {
dispatch(socketInvocationStarted({ data, timestamp: getTimestamp() }));
dispatch(socketInvocationStarted({ data }));
});
/**
* Generator progress
*/
socket.on('generator_progress', (data) => {
dispatch(socketGeneratorProgress({ data, timestamp: getTimestamp() }));
dispatch(socketGeneratorProgress({ data }));
});
/**
* Invocation error
*/
socket.on('invocation_error', (data) => {
dispatch(socketInvocationError({ data, timestamp: getTimestamp() }));
dispatch(socketInvocationError({ data }));
});
/**
@ -104,7 +104,6 @@ export const setEventListeners = (arg: SetEventListenersArg) => {
dispatch(
socketInvocationComplete({
data,
timestamp: getTimestamp(),
})
);
});
@ -116,7 +115,6 @@ export const setEventListeners = (arg: SetEventListenersArg) => {
dispatch(
socketGraphExecutionStateComplete({
data,
timestamp: getTimestamp(),
})
);
});
@ -128,7 +126,6 @@ export const setEventListeners = (arg: SetEventListenersArg) => {
dispatch(
socketModelLoadStarted({
data,
timestamp: getTimestamp(),
})
);
});
@ -140,7 +137,28 @@ export const setEventListeners = (arg: SetEventListenersArg) => {
dispatch(
socketModelLoadCompleted({
data,
timestamp: getTimestamp(),
})
);
});
/**
* Session retrieval error
*/
socket.on('session_retrieval_error', (data) => {
dispatch(
socketSessionRetrievalError({
data,
})
);
});
/**
* Invocation retrieval error
*/
socket.on('invocation_retrieval_error', (data) => {
dispatch(
socketInvocationRetrievalError({
data,
})
);
});