mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
feat: add link to low vram guide to OOM toast (local only)
Needed to do a bit of refactoring to support this. Overall, the error toast components are easier to understand now.
This commit is contained in:
@@ -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",
|
||||
@@ -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": {
|
||||
|
||||
@@ -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';
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
const ERROR_TYPE_TO_TITLE: Record<string, string> = {
|
||||
OutOfMemoryError: 'toast.outOfMemoryError',
|
||||
};
|
||||
|
||||
const COMMERCIAL_ERROR_TYPE_TO_DESC: Record<string, string> = {
|
||||
OutOfMemoryError: 'toast.outOfMemoryErrorDesc',
|
||||
};
|
||||
|
||||
export const getTitleFromErrorType = (errorType: string) => {
|
||||
return t(ERROR_TYPE_TO_TITLE[errorType] ?? 'toast.serverError');
|
||||
};
|
||||
|
||||
type Props = { errorType: string; errorMessage?: string | null; sessionId: string; isLocal: boolean };
|
||||
|
||||
export default function ErrorToastDescription({ errorType, errorMessage, sessionId, isLocal }: Props) {
|
||||
export const ErrorToastTitle = ({ errorType }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (errorType === 'OutOfMemoryError') {
|
||||
return t('toast.outOfMemoryError');
|
||||
}
|
||||
|
||||
return t('toast.serverError');
|
||||
};
|
||||
|
||||
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 && (
|
||||
@@ -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' } };
|
||||
|
||||
@@ -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';
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user