feat(ui): improve session invoked handling

This commit is contained in:
psychedelicious 2023-05-26 16:17:12 +10:00
parent 8f190169db
commit b599c40099
6 changed files with 115 additions and 91 deletions

View File

@ -546,7 +546,6 @@
"availableSchedulers": "Available Schedulers" "availableSchedulers": "Available Schedulers"
}, },
"toast": { "toast": {
"problemCreatingSession": "Problem Creating Session",
"serverError": "Server Error", "serverError": "Server Error",
"disconnected": "Disconnected from Server", "disconnected": "Disconnected from Server",
"connected": "Connected to Server", "connected": "Connected to Server",

View File

@ -49,6 +49,11 @@ import {
addSessionCreatedPendingListener, addSessionCreatedPendingListener,
addSessionCreatedRejectedListener, addSessionCreatedRejectedListener,
} from './listeners/sessionCreated'; } from './listeners/sessionCreated';
import {
addSessionInvokedFulfilledListener,
addSessionInvokedPendingListener,
addSessionInvokedRejectedListener,
} from './listeners/sessionInvoked';
export const listenerMiddleware = createListenerMiddleware(); export const listenerMiddleware = createListenerMiddleware();
@ -88,13 +93,18 @@ addImageMetadataReceivedRejectedListener();
addImageUrlsReceivedFulfilledListener(); addImageUrlsReceivedFulfilledListener();
addImageUrlsReceivedRejectedListener(); addImageUrlsReceivedRejectedListener();
// Invoking stuff // Invoking on tabs
addUserInvokedCanvasListener(); addUserInvokedCanvasListener();
addUserInvokedNodesListener(); addUserInvokedNodesListener();
addUserInvokedTextToImageListener(); addUserInvokedTextToImageListener();
addUserInvokedImageToImageListener(); addUserInvokedImageToImageListener();
addSessionReadyToInvokeListener(); addSessionReadyToInvokeListener();
// Actual session invoking
addSessionInvokedPendingListener();
addSessionInvokedFulfilledListener();
addSessionInvokedRejectedListener();
// Canvas actions // Canvas actions
addCanvasSavedToGalleryListener(); addCanvasSavedToGalleryListener();
addCanvasDownloadedAsImageListener(); addCanvasDownloadedAsImageListener();

View File

@ -0,0 +1,45 @@
import { log } from 'app/logging/useLogger';
import { startAppListening } from '..';
import { sessionInvoked } from 'services/thunks/session';
import { serializeError } from 'serialize-error';
const moduleLog = log.child({ namespace: 'session' });
export const addSessionInvokedPendingListener = () => {
startAppListening({
actionCreator: sessionInvoked.pending,
effect: (action, { getState, dispatch }) => {
//
},
});
};
export const addSessionInvokedFulfilledListener = () => {
startAppListening({
actionCreator: sessionInvoked.fulfilled,
effect: (action, { getState, dispatch }) => {
const { sessionId } = action.meta.arg;
moduleLog.info({ data: { sessionId } }, `Session invoked (${sessionId})`);
},
});
};
export const addSessionInvokedRejectedListener = () => {
startAppListening({
actionCreator: sessionInvoked.rejected,
effect: (action, { getState, dispatch }) => {
if (action.payload) {
const { arg, error } = action.payload;
moduleLog.error(
{
data: {
arg,
error: serializeError(error),
},
},
`Problem invoking session`
);
}
},
});
};

View File

@ -3,7 +3,7 @@ import { sessionInvoked } from 'services/thunks/session';
import { log } from 'app/logging/useLogger'; import { log } from 'app/logging/useLogger';
import { sessionReadyToInvoke } from 'features/system/store/actions'; import { sessionReadyToInvoke } from 'features/system/store/actions';
const moduleLog = log.child({ namespace: 'invoke' }); const moduleLog = log.child({ namespace: 'session' });
export const addSessionReadyToInvokeListener = () => { export const addSessionReadyToInvokeListener = () => {
startAppListening({ startAppListening({
@ -11,7 +11,10 @@ export const addSessionReadyToInvokeListener = () => {
effect: (action, { getState, dispatch }) => { effect: (action, { getState, dispatch }) => {
const { sessionId } = getState().system; const { sessionId } = getState().system;
if (sessionId) { if (sessionId) {
moduleLog.info({ sessionId }, `Session invoked (${sessionId})})`); moduleLog.info(
{ sessionId },
`Session ready to invoke (${sessionId})})`
);
dispatch(sessionInvoked({ sessionId })); dispatch(sessionInvoked({ sessionId }));
} }
}, },

View File

@ -1,5 +1,5 @@
import { UseToastOptions } from '@chakra-ui/react'; import { UseToastOptions } from '@chakra-ui/react';
import type { PayloadAction } from '@reduxjs/toolkit'; import { PayloadAction, isAnyOf } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit';
import * as InvokeAI from 'app/types/invokeai'; import * as InvokeAI from 'app/types/invokeai';
import { import {
@ -349,13 +349,6 @@ export const systemSlice = createSlice({
state.statusTranslationKey = 'common.statusPreparing'; state.statusTranslationKey = 'common.statusPreparing';
}); });
builder.addCase(sessionInvoked.rejected, (state, action) => {
const error = action.payload as string | undefined;
state.toastQueue.push(
makeToast({ title: error || t('toast.serverError'), status: 'error' })
);
});
/** /**
* Session Canceled - FULFILLED * Session Canceled - FULFILLED
*/ */
@ -374,23 +367,6 @@ export const systemSlice = createSlice({
); );
}); });
/**
* Session Created - REJECTED
*/
builder.addCase(sessionCreated.rejected, (state, action) => {
state.isProcessing = false;
state.isCancelable = false;
state.isCancelScheduled = false;
state.currentStep = 0;
state.totalSteps = 0;
state.statusTranslationKey = 'common.statusConnected';
state.progressImage = null;
state.toastQueue.push(
makeToast({ title: t('toast.problemCreatingSession'), status: 'error' })
);
});
/** /**
* Session Canceled * Session Canceled
*/ */
@ -437,6 +413,26 @@ export const systemSlice = createSlice({
builder.addCase(imageUploaded.fulfilled, (state) => { builder.addCase(imageUploaded.fulfilled, (state) => {
state.isUploading = false; state.isUploading = false;
}); });
// *** Matchers - must be after all cases ***
/**
* Session Invoked - REJECTED
* Session Created - REJECTED
*/
builder.addMatcher(isAnySessionRejected, (state, action) => {
state.isProcessing = false;
state.isCancelable = false;
state.isCancelScheduled = false;
state.currentStep = 0;
state.totalSteps = 0;
state.statusTranslationKey = 'common.statusConnected';
state.progressImage = null;
state.toastQueue.push(
makeToast({ title: t('toast.serverError'), status: 'error' })
);
});
}, },
}); });
@ -465,3 +461,8 @@ export const {
} = systemSlice.actions; } = systemSlice.actions;
export default systemSlice.reducer; export default systemSlice.reducer;
const isAnySessionRejected = isAnyOf(
sessionCreated.rejected,
sessionInvoked.rejected
);

View File

@ -1,6 +1,7 @@
import { createAppAsyncThunk } from 'app/store/storeUtils'; import { createAppAsyncThunk } from 'app/store/storeUtils';
import { GraphExecutionState, SessionsService } from 'services/api'; import { GraphExecutionState, SessionsService } from 'services/api';
import { log } from 'app/logging/useLogger'; import { log } from 'app/logging/useLogger';
import { isObject } from 'lodash-es';
const sessionLog = log.child({ namespace: 'session' }); const sessionLog = log.child({ namespace: 'session' });
@ -21,7 +22,7 @@ export const sessionCreated = createAppAsyncThunk<
GraphExecutionState, GraphExecutionState,
SessionCreatedArg, SessionCreatedArg,
SessionCreatedThunkConfig SessionCreatedThunkConfig
>('api/sessionCreated', async (arg: SessionCreatedArg, { rejectWithValue }) => { >('api/sessionCreated', async (arg, { rejectWithValue }) => {
try { try {
const response = await SessionsService.createSession({ const response = await SessionsService.createSession({
requestBody: arg.graph, requestBody: arg.graph,
@ -32,57 +33,26 @@ export const sessionCreated = createAppAsyncThunk<
} }
}); });
type NodeAddedArg = Parameters<(typeof SessionsService)['addNode']>[0]; type SessionInvokedArg = { sessionId: string };
/** type SessionInvokedThunkConfig = {
* `SessionsService.addNode()` thunk rejectValue: {
*/ arg: SessionInvokedArg;
export const nodeAdded = createAppAsyncThunk( error: unknown;
'api/nodeAdded', };
async ( };
arg: { node: NodeAddedArg['requestBody']; sessionId: string },
_thunkApi
) => {
const response = await SessionsService.addNode({
requestBody: arg.node,
sessionId: arg.sessionId,
});
sessionLog.info({ arg, response }, `Node added (${response})`); const isErrorWithStatus = (error: unknown): error is { status: number } =>
isObject(error) && 'status' in error;
return response;
}
);
type NodeUpdatedArg = Parameters<(typeof SessionsService)['updateNode']>[0];
/**
* `SessionsService.addNode()` thunk
*/
export const nodeUpdated = createAppAsyncThunk(
'api/nodeUpdated',
async (
arg: { node: NodeUpdatedArg['requestBody']; sessionId: string },
_thunkApi
) => {
const response = await SessionsService.updateNode({
requestBody: arg.node,
sessionId: arg.sessionId,
nodePath: arg.node.id,
});
sessionLog.info({ arg, response }, `Node updated (${response})`);
return response;
}
);
/** /**
* `SessionsService.invokeSession()` thunk * `SessionsService.invokeSession()` thunk
*/ */
export const sessionInvoked = createAppAsyncThunk( export const sessionInvoked = createAppAsyncThunk<
'api/sessionInvoked', any,
async (arg: { sessionId: string }, { rejectWithValue }) => { SessionInvokedArg,
SessionInvokedThunkConfig
>('api/sessionInvoked', async (arg, { rejectWithValue }) => {
const { sessionId } = arg; const { sessionId } = arg;
try { try {
@ -90,18 +60,14 @@ export const sessionInvoked = createAppAsyncThunk(
sessionId, sessionId,
all: true, all: true,
}); });
sessionLog.info({ arg, response }, `Session invoked (${sessionId})`);
return response; return response;
} catch (error) { } catch (error) {
const err = error as any; if (isErrorWithStatus(error) && error.status === 403) {
if (err.status === 403) { return rejectWithValue({ arg, error: (error as any).body.detail });
return rejectWithValue(err.body.detail);
} }
throw error; return rejectWithValue({ arg, error });
} }
} });
);
type SessionCanceledArg = Parameters< type SessionCanceledArg = Parameters<
(typeof SessionsService)['cancelSessionInvoke'] (typeof SessionsService)['cancelSessionInvoke']