mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-15 20:35:26 -05:00
feat(ui): ability to disable generating with API models
This commit is contained in:
committed by
psychedelicious
parent
ff897f74a1
commit
548e766c0b
@@ -5,6 +5,7 @@ import type { StudioInitAction } from 'app/hooks/useStudioInitAction';
|
||||
import { $didStudioInit } from 'app/hooks/useStudioInitAction';
|
||||
import type { LoggingOverrides } from 'app/logging/logger';
|
||||
import { $loggingOverrides, configureLogging } from 'app/logging/logger';
|
||||
import { $accountSettingsLink } from 'app/store/nanostores/accountSettingsLink';
|
||||
import { $authToken } from 'app/store/nanostores/authToken';
|
||||
import { $baseUrl } from 'app/store/nanostores/baseUrl';
|
||||
import { $customNavComponent } from 'app/store/nanostores/customNavComponent';
|
||||
@@ -46,6 +47,7 @@ interface Props extends PropsWithChildren {
|
||||
token?: string;
|
||||
config?: PartialAppConfig;
|
||||
customNavComponent?: ReactNode;
|
||||
accountSettingsLink?: string;
|
||||
middleware?: Middleware[];
|
||||
projectId?: string;
|
||||
projectName?: string;
|
||||
@@ -72,6 +74,7 @@ const InvokeAIUI = ({
|
||||
token,
|
||||
config,
|
||||
customNavComponent,
|
||||
accountSettingsLink,
|
||||
middleware,
|
||||
projectId,
|
||||
projectName,
|
||||
@@ -175,6 +178,16 @@ const InvokeAIUI = ({
|
||||
};
|
||||
}, [customNavComponent]);
|
||||
|
||||
useEffect(() => {
|
||||
if (accountSettingsLink) {
|
||||
$accountSettingsLink.set(accountSettingsLink);
|
||||
}
|
||||
|
||||
return () => {
|
||||
$accountSettingsLink.set(undefined);
|
||||
};
|
||||
}, [accountSettingsLink]);
|
||||
|
||||
useEffect(() => {
|
||||
if (openAPISchemaUrl) {
|
||||
$openAPISchemaUrl.set(openAPISchemaUrl);
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { atom } from 'nanostores';
|
||||
|
||||
export const $accountSettingsLink = atom<string | undefined>(undefined);
|
||||
@@ -28,7 +28,8 @@ export type AppFeature =
|
||||
| 'starterModels'
|
||||
| 'hfToken'
|
||||
| 'retryQueueItem'
|
||||
| 'cancelAndClearAll';
|
||||
| 'cancelAndClearAll'
|
||||
| 'apiModels';
|
||||
/**
|
||||
* A disable-able Stable Diffusion feature
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { Flex, Link, Text } from '@invoke-ai/ui-library';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { $accountSettingsLink } from 'app/store/nanostores/accountSettingsLink';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectIsChatGTP4o, selectIsImagen3, selectModel } from 'features/controlLayers/store/paramsSlice';
|
||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||
import { useMemo } from 'react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
|
||||
export const DisabledModelWarning = () => {
|
||||
const { t } = useTranslation();
|
||||
const model = useAppSelector(selectModel);
|
||||
const isImagen3 = useAppSelector(selectIsImagen3);
|
||||
const isChatGPT4o = useAppSelector(selectIsChatGTP4o);
|
||||
const areApiModelsEnabled = useFeatureStatus('apiModels');
|
||||
const accountSettingsLink = useStore($accountSettingsLink);
|
||||
|
||||
const isModelDisabled = useMemo(() => {
|
||||
return (isImagen3 || isChatGPT4o) && !areApiModelsEnabled;
|
||||
}, [isImagen3, isChatGPT4o, areApiModelsEnabled]);
|
||||
|
||||
if (!isModelDisabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex bg="error.500" borderRadius="base" padding={4} direction="column" fontSize="sm" gap={2}>
|
||||
<Text>
|
||||
<Trans
|
||||
i18nKey="parameters.modelDisabledForTrial"
|
||||
values={{
|
||||
modelName: model?.name,
|
||||
}}
|
||||
components={{
|
||||
LinkComponent: (
|
||||
<Link textDecor="underline" href={accountSettingsLink}>
|
||||
{t('parameters.invoke.accountSettings')}
|
||||
</Link>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
@@ -14,6 +14,8 @@ import { MdMoneyOff } from 'react-icons/md';
|
||||
import { useMainModels } from 'services/api/hooks/modelsByType';
|
||||
import { type AnyModelConfig, isCheckpointMainModelConfig, type MainModelConfig } from 'services/api/types';
|
||||
|
||||
import { DisabledModelWarning } from './DisabledModelWarning';
|
||||
|
||||
const ParamMainModelSelect = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
@@ -79,32 +81,35 @@ const ParamMainModelSelect = () => {
|
||||
}, [selectedModel]);
|
||||
|
||||
return (
|
||||
<FormControl isDisabled={!modelConfigs.length} isInvalid={!value || !modelConfigs.length} gap={2}>
|
||||
<InformationalPopover feature="paramModel">
|
||||
<FormLabel>{t('modelManager.model')}</FormLabel>
|
||||
</InformationalPopover>
|
||||
{isFluxDevSelected && (
|
||||
<InformationalPopover feature="fluxDevLicense" hideDisable={true}>
|
||||
<Flex justifyContent="flex-start">
|
||||
<Icon as={MdMoneyOff} />
|
||||
</Flex>
|
||||
<>
|
||||
<DisabledModelWarning />
|
||||
<FormControl isDisabled={!modelConfigs.length} isInvalid={!value || !modelConfigs.length} gap={2}>
|
||||
<InformationalPopover feature="paramModel">
|
||||
<FormLabel>{t('modelManager.model')}</FormLabel>
|
||||
</InformationalPopover>
|
||||
)}
|
||||
<Tooltip label={tooltipLabel}>
|
||||
<Box w="full" minW={0}>
|
||||
<Combobox
|
||||
value={value}
|
||||
placeholder={placeholder}
|
||||
options={options}
|
||||
onChange={onChange}
|
||||
noOptionsMessage={noOptionsMessage}
|
||||
isInvalid={value?.isDisabled}
|
||||
/>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
<NavigateToModelManagerButton />
|
||||
<UseDefaultSettingsButton />
|
||||
</FormControl>
|
||||
{isFluxDevSelected && (
|
||||
<InformationalPopover feature="fluxDevLicense" hideDisable={true}>
|
||||
<Flex justifyContent="flex-start">
|
||||
<Icon as={MdMoneyOff} />
|
||||
</Flex>
|
||||
</InformationalPopover>
|
||||
)}
|
||||
<Tooltip label={tooltipLabel}>
|
||||
<Box w="full" minW={0}>
|
||||
<Combobox
|
||||
value={value}
|
||||
placeholder={placeholder}
|
||||
options={options}
|
||||
onChange={onChange}
|
||||
noOptionsMessage={noOptionsMessage}
|
||||
isInvalid={value?.isDisabled}
|
||||
/>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
<NavigateToModelManagerButton />
|
||||
<UseDefaultSettingsButton />
|
||||
</FormControl>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import { resolveBatchValue } from 'features/nodes/util/node/resolveBatchValue';
|
||||
import type { UpscaleState } from 'features/parameters/store/upscaleSlice';
|
||||
import { selectUpscaleSlice } from 'features/parameters/store/upscaleSlice';
|
||||
import { getGridSize } from 'features/parameters/util/optimalDimension';
|
||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||
import { selectConfigSlice } from 'features/system/store/configSlice';
|
||||
import { selectActiveTab } from 'features/ui/store/uiSelectors';
|
||||
import type { TabName } from 'features/ui/store/uiTypes';
|
||||
@@ -87,7 +88,8 @@ const debouncedUpdateReasons = debounce(
|
||||
upscale: UpscaleState,
|
||||
config: AppConfig,
|
||||
store: AppStore,
|
||||
isInPublishFlow: boolean
|
||||
isInPublishFlow: boolean,
|
||||
areApiModelsEnabled: boolean
|
||||
) => {
|
||||
if (tab === 'canvas') {
|
||||
const model = selectMainModelConfig(store.getState());
|
||||
@@ -102,6 +104,7 @@ const debouncedUpdateReasons = debounce(
|
||||
canvasIsRasterizing,
|
||||
canvasIsCompositing,
|
||||
canvasIsSelectingObject,
|
||||
areApiModelsEnabled,
|
||||
});
|
||||
$reasonsWhyCannotEnqueue.set(reasons);
|
||||
} else if (tab === 'workflows') {
|
||||
@@ -149,6 +152,7 @@ export const useReadinessWatcher = () => {
|
||||
const canvasIsSelectingObject = useStore(canvasManager?.stateApi.$isSegmenting ?? $true);
|
||||
const canvasIsCompositing = useStore(canvasManager?.compositor.$isBusy ?? $true);
|
||||
const isInPublishFlow = useStore($isInPublishFlow);
|
||||
const areApiModelsEnabled = useFeatureStatus('apiModels');
|
||||
|
||||
useEffect(() => {
|
||||
debouncedUpdateReasons(
|
||||
@@ -168,7 +172,8 @@ export const useReadinessWatcher = () => {
|
||||
upscale,
|
||||
config,
|
||||
store,
|
||||
isInPublishFlow
|
||||
isInPublishFlow,
|
||||
areApiModelsEnabled
|
||||
);
|
||||
}, [
|
||||
store,
|
||||
@@ -188,6 +193,7 @@ export const useReadinessWatcher = () => {
|
||||
upscale,
|
||||
workflowSettings,
|
||||
isInPublishFlow,
|
||||
areApiModelsEnabled,
|
||||
]);
|
||||
};
|
||||
|
||||
@@ -335,6 +341,7 @@ const getReasonsWhyCannotEnqueueCanvasTab = (arg: {
|
||||
canvasIsRasterizing: boolean;
|
||||
canvasIsCompositing: boolean;
|
||||
canvasIsSelectingObject: boolean;
|
||||
areApiModelsEnabled: boolean;
|
||||
}) => {
|
||||
const {
|
||||
isConnected,
|
||||
@@ -347,6 +354,7 @@ const getReasonsWhyCannotEnqueueCanvasTab = (arg: {
|
||||
canvasIsRasterizing,
|
||||
canvasIsCompositing,
|
||||
canvasIsSelectingObject,
|
||||
areApiModelsEnabled,
|
||||
} = arg;
|
||||
const { positivePrompt } = params;
|
||||
const reasons: Reason[] = [];
|
||||
@@ -479,6 +487,10 @@ const getReasonsWhyCannotEnqueueCanvasTab = (arg: {
|
||||
}
|
||||
}
|
||||
|
||||
if ((model?.base === 'imagen3' || model?.base === 'chatgpt-4o') && !areApiModelsEnabled) {
|
||||
reasons.push({ content: i18n.t('parameters.invoke.modelDisabledForTrial', { modelName: model.name }) });
|
||||
}
|
||||
|
||||
const enabledControlLayers = canvas.controlLayers.entities.filter((controlLayer) => controlLayer.isEnabled);
|
||||
|
||||
// FLUX only supports 1x Control LoRA at a time.
|
||||
|
||||
@@ -27,6 +27,7 @@ import { typedMemo } from 'common/util/typedMemo';
|
||||
import { $installModelsTab } from 'features/modelManagerV2/subpanels/InstallModels';
|
||||
import { BASE_COLOR_MAP } from 'features/modelManagerV2/subpanels/ModelManagerPanel/ModelBaseBadge';
|
||||
import ModelImage from 'features/modelManagerV2/subpanels/ModelManagerPanel/ModelImage';
|
||||
import { DisabledModelWarning } from 'features/parameters/components/MainModel/DisabledModelWarning';
|
||||
import { NavigateToModelManagerButton } from 'features/parameters/components/MainModel/NavigateToModelManagerButton';
|
||||
import { UseDefaultSettingsButton } from 'features/parameters/components/MainModel/UseDefaultSettingsButton';
|
||||
import { modelSelected } from 'features/parameters/store/actions';
|
||||
@@ -200,6 +201,7 @@ export const MainModelPicker = memo(() => {
|
||||
onClose={onClose}
|
||||
initialFocusRef={pickerRef.current?.inputRef}
|
||||
>
|
||||
<DisabledModelWarning />
|
||||
<Flex alignItems="center" gap={2}>
|
||||
<InformationalPopover feature="paramModel">
|
||||
<FormLabel>{t('modelManager.model')}</FormLabel>
|
||||
|
||||
Reference in New Issue
Block a user