Skip to content

Commit

Permalink
feat: add link to low vram guide to OOM toast (local only)
Browse files Browse the repository at this point in the history
Needed to do a bit of refactoring to support this. Overall, the error toast components are easier to understand now.
  • Loading branch information
psychedelicious committed Jan 9, 2025
1 parent e09cf64 commit a329588
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 49 deletions.
3 changes: 2 additions & 1 deletion invokeai/frontend/web/public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,7 @@
"modelAddedSimple": "Model Added to Queue",
"modelImportCanceled": "Model Import Canceled",
"outOfMemoryError": "Out of Memory Error",
"outOfMemoryErrorDescLocal": "Follow our <LinkComponent>Low VRAM guide</LinkComponent> to reduce OOMs.",
"outOfMemoryErrorDesc": "Your current generation settings exceed system capacity. Please adjust your settings and try again.",
"parameters": "Parameters",
"parameterSet": "Parameter Recalled",
Expand Down Expand Up @@ -2133,7 +2134,7 @@
"toGetStartedLocal": "To get started, make sure to download or import models needed to run Invoke. Then, enter a prompt in the box and click <StrongComponent>Invoke</StrongComponent> to generate your first image. Select a prompt template to improve results. You can choose to save your images directly to the <StrongComponent>Gallery</StrongComponent> or edit them to the <StrongComponent>Canvas</StrongComponent>.",
"toGetStarted": "To get started, enter a prompt in the box and click <StrongComponent>Invoke</StrongComponent> to generate your first image. Select a prompt template to improve results. You can choose to save your images directly to the <StrongComponent>Gallery</StrongComponent> or edit them to the <StrongComponent>Canvas</StrongComponent>.",
"gettingStartedSeries": "Want more guidance? Check out our <LinkComponent>Getting Started Series</LinkComponent> for tips on unlocking the full potential of the Invoke Studio.",
"lowVRAMMode": "For best performance, follow our <LinkComponent>Low VRAM mode guide</LinkComponent>.",
"lowVRAMMode": "For best performance, follow our <LinkComponent>Low VRAM guide</LinkComponent>.",
"noModelsInstalled": "It looks like you don't have any models installed! You can <DownloadStarterModelsButton>download a starter model bundle</DownloadStarterModelsButton> or <ImportModelsButton>import models</ImportModelsButton>."
},
"whatsNew": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
import {
Alert,
AlertDescription,
AlertIcon,
Button,
Divider,
Flex,
Icon,
Link,
Spinner,
Text,
} from '@invoke-ai/ui-library';
import type { ButtonProps } from '@invoke-ai/ui-library';
import { Alert, AlertDescription, AlertIcon, Button, Divider, Flex, Link, Spinner, Text } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
import { InvokeLogoIcon } from 'common/components/InvokeLogoIcon';
Expand Down Expand Up @@ -71,20 +61,19 @@ const LoadingSpinner = () => {
);
};

const ExternalLink = (props: PropsWithChildren<{ href: string }>) => {
export const ExternalLink = (props: ButtonProps & { href: string }) => {
return (
<Button
as={Link}
variant="link"
variant="unstyled"
isExternal
display="inline-flex"
alignItems="center"
href={props.href}
rightIcon={<PiArrowSquareOutBold />}
color="base.50"
>
{props.children}
<Icon display="inline" verticalAlign="middle" marginInlineStart={2} as={PiArrowSquareOutBold} />
</Button>
mt={-1}
{...props}
/>
);
};

Expand Down
58 changes: 31 additions & 27 deletions invokeai/frontend/web/src/features/toast/ErrorToastDescription.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,45 @@
import { Flex, IconButton, Text } from '@invoke-ai/ui-library';
import { t } from 'i18next';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { ExternalLink } from 'features/gallery/components/ImageViewer/NoContentForViewer';
import { useCallback, useMemo } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { PiCopyBold } from 'react-icons/pi';

function onCopy(sessionId: string) {
navigator.clipboard.writeText(sessionId);
}
type Props = { errorType: string; errorMessage?: string | null; sessionId: string; isLocal: boolean };

const ERROR_TYPE_TO_TITLE: Record<string, string> = {
OutOfMemoryError: 'toast.outOfMemoryError',
};
export const ErrorToastTitle = ({ errorType }: Props) => {
const { t } = useTranslation();

const COMMERCIAL_ERROR_TYPE_TO_DESC: Record<string, string> = {
OutOfMemoryError: 'toast.outOfMemoryErrorDesc',
};
if (errorType === 'OutOfMemoryError') {
return t('toast.outOfMemoryError');
}

export const getTitleFromErrorType = (errorType: string) => {
return t(ERROR_TYPE_TO_TITLE[errorType] ?? 'toast.serverError');
return t('toast.serverError');
};

type Props = { errorType: string; errorMessage?: string | null; sessionId: string; isLocal: boolean };

export default function ErrorToastDescription({ errorType, errorMessage, sessionId, isLocal }: Props) {
export default function ErrorToastDescription({ errorType, isLocal, sessionId, errorMessage }: Props) {
const { t } = useTranslation();

const description = useMemo(() => {
// Special handling for commercial error types
const descriptionTKey = isLocal ? null : COMMERCIAL_ERROR_TYPE_TO_DESC[errorType];
if (descriptionTKey) {
return t(descriptionTKey);
}
if (errorMessage) {
if (errorType === 'OutOfMemoryError') {
if (isLocal) {
return (
<Trans
i18nKey="toast.outOfMemoryErrorDescLocal"
components={{
LinkComponent: <ExternalLink href="https://invoke-ai.github.io/InvokeAI/features/low-vram/" />,
}}
/>
);
} else {
return t('toast.outOfMemoryErrorDesc');
}
} else if (errorMessage) {
return `${errorType}: ${errorMessage}`;
}
}, [errorMessage, errorType, isLocal, t]);

const copySessionId = useCallback(() => navigator.clipboard.writeText(sessionId), [sessionId]);

return (
<Flex flexDir="column">
{description && (
Expand All @@ -50,14 +56,12 @@ export default function ErrorToastDescription({ errorType, errorMessage, session
size="sm"
aria-label="Copy"
icon={<PiCopyBold />}
onClick={onCopy.bind(null, sessionId)}
onClick={copySessionId}
variant="ghost"
sx={sx}
sx={{ svg: { fill: 'base.50' } }}
/>
</Flex>
)}
</Flex>
);
}

const sx = { svg: { fill: 'base.50' } };
11 changes: 9 additions & 2 deletions invokeai/frontend/web/src/services/events/setEventListeners.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { AppStore } from 'app/store/store';
import { deepClone } from 'common/util/deepClone';
import { $nodeExecutionStates, upsertExecutionState } from 'features/nodes/hooks/useExecutionState';
import { zNodeStatus } from 'features/nodes/types/invocation';
import ErrorToastDescription, { getTitleFromErrorType } from 'features/toast/ErrorToastDescription';
import ErrorToastDescription, { ErrorToastTitle } from 'features/toast/ErrorToastDescription';
import { toast } from 'features/toast/toast';
import { t } from 'i18next';
import { forEach, isNil, round } from 'lodash-es';
Expand Down Expand Up @@ -400,7 +400,14 @@ export const setEventListeners = ({ socket, store, setIsConnected }: SetEventLis

toast({
id: `INVOCATION_ERROR_${error_type}`,
title: getTitleFromErrorType(error_type),
title: (
<ErrorToastTitle
errorType={error_type}
errorMessage={error_message}
sessionId={sessionId}
isLocal={isLocal}
/>
),
status: 'error',
duration: null,
updateDescription: isLocal,
Expand Down

0 comments on commit a329588

Please sign in to comment.