diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index c44298de665..8fc600d6c96 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1643,19 +1643,16 @@ }, "upscaling": { "creativity": "Creativity", - "currentImageSize": "Current Image Size", - "outputImageSize": "Output Image Size", - "sharpness": "Sharpness", "structure": "Structure", - "toInstall": "to install", - "upscaleModel": "Upcale Model", + "upscaleModel": "Upscale Model", "scale": "Scale", - "visit": "Visit", - "warningNoMainModel": "a model", - "warningNoTile": "a {{base_model}} tile controlnet required by this feature", - "warningNoTileOrUpscaleModel": "an upscaler model and {{base_model}} tile controlnet required by this feature", - "warningNoUpscaleModel": "an upscaler model required by this feature", - "upscalingFromTo": "Upscaling from {{from}} to {{to}}" + "missingModelsWarning": "Visit the Model Manager to install the required models:", + "mainModelDesc": "Main model (SD1.5 or SDXL architecture)", + "tileControlNetModelDesc": "Tile ControlNet model for the chosen main model architecture", + "upscaleModelDesc": "Upscale (image to image) model", + "missingUpscaleInitialImage": "Missing initial image for upscaling", + "missingUpscaleModel": "Missing upscale model", + "missingTileControlNetModel": "No valid tile ControlNet models installed" }, "ui": { "tabs": { diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedUpscale.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedUpscale.ts index f51f9e75647..dc870a9f8b5 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedUpscale.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedUpscale.ts @@ -2,7 +2,7 @@ import { enqueueRequested } from 'app/store/actions'; import type { AppStartListening } from 'app/store/middleware/listenerMiddleware'; import { isImageViewerOpenChanged } from 'features/gallery/store/gallerySlice'; import { prepareLinearUIBatch } from 'features/nodes/util/graph/buildLinearBatchConfig'; -import { buildMultidiffusionUpscsaleGraph } from 'features/nodes/util/graph/buildMultidiffusionUpscaleGraph'; +import { buildMultidiffusionUpscaleGraph } from 'features/nodes/util/graph/buildMultidiffusionUpscaleGraph'; import { queueApi } from 'services/api/endpoints/queue'; export const addEnqueueRequestedUpscale = (startAppListening: AppStartListening) => { @@ -14,7 +14,7 @@ export const addEnqueueRequestedUpscale = (startAppListening: AppStartListening) const { shouldShowProgressInViewer } = state.ui; const { prepend } = action.payload; - const graph = await buildMultidiffusionUpscsaleGraph(state); + const graph = await buildMultidiffusionUpscaleGraph(state); const batchConfig = prepareLinearUIBatch(state, graph, prepend); diff --git a/invokeai/frontend/web/src/common/hooks/useIsReadyToEnqueue.ts b/invokeai/frontend/web/src/common/hooks/useIsReadyToEnqueue.ts index 9c465bb3cc1..ba2117f2075 100644 --- a/invokeai/frontend/web/src/common/hooks/useIsReadyToEnqueue.ts +++ b/invokeai/frontend/web/src/common/hooks/useIsReadyToEnqueue.ts @@ -208,14 +208,13 @@ const createSelector = (templates: Templates) => }); } else if (activeTabName === 'upscaling') { if (!upscale.upscaleInitialImage) { - reasons.push({ content: 'No Initial image' }); + reasons.push({ content: i18n.t('upscaling.missingUpscaleInitialImage') }); } if (!upscale.upscaleModel) { - reasons.push({ content: 'No upscale model selected' }); + reasons.push({ content: i18n.t('upscaling.missingUpscaleModel') }); } - if (!upscale.tileControlnetModel) { - reasons.push({ content: 'No valid tile controlnet available' }); + reasons.push({ content: i18n.t('upscaling.missingTileControlNetModel') }); } } else { // Handling for all other tabs diff --git a/invokeai/frontend/web/src/features/modelManagerV2/hooks/useStarterModelsToast.tsx b/invokeai/frontend/web/src/features/modelManagerV2/hooks/useStarterModelsToast.tsx index 6da320aa0b7..101394f85ac 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/hooks/useStarterModelsToast.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/hooks/useStarterModelsToast.tsx @@ -1,5 +1,6 @@ import { Button, Text, useToast } from '@invoke-ai/ui-library'; import { useAppDispatch } from 'app/store/storeHooks'; +import { $installModelsTab } from 'features/modelManagerV2/subpanels/InstallModels'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { setActiveTab } from 'features/ui/store/uiSlice'; import { useCallback, useEffect, useState } from 'react'; @@ -44,6 +45,7 @@ const ToastDescription = () => { const onClick = useCallback(() => { dispatch(setActiveTab('models')); + $installModelsTab.set(3); toast.close(TOAST_ID); }, [dispatch, toast]); diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StartModelsResultItem.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StartModelsResultItem.tsx index 98e1e396404..754cbbd25ab 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StartModelsResultItem.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StartModelsResultItem.tsx @@ -30,7 +30,7 @@ export const StarterModelsResultItem = ({ result }: Props) => { - {result.type.replace('_', ' ')} + {result.type.replaceAll('_', ' ')} {result.name} diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StarterModelsResults.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StarterModelsResults.tsx index 7aa05af3004..ccaa29d5e25 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StarterModelsResults.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StarterModelsResults.tsx @@ -18,14 +18,17 @@ export const StarterModelsResults = ({ results }: StarterModelsResultsProps) => const filteredResults = useMemo(() => { return results.filter((result) => { - const name = result.name.toLowerCase(); - const type = result.type.toLowerCase(); - return name.includes(searchTerm.toLowerCase()) || type.includes(searchTerm.toLowerCase()); + const trimmedSearchTerm = searchTerm.trim().toLowerCase(); + const matchStrings = [result.name.toLowerCase(), result.type.toLowerCase(), result.description.toLowerCase()]; + if (result.type === 'spandrel_image_to_image') { + matchStrings.push('upscale'); + } + return matchStrings.some((matchString) => matchString.includes(trimmedSearchTerm)); }); }, [results, searchTerm]); const handleSearch: ChangeEventHandler = useCallback((e) => { - setSearchTerm(e.target.value.trim()); + setSearchTerm(e.target.value); }, []); const clearSearch = useCallback(() => { diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/InstallModels.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/InstallModels.tsx index d09ab67fa4a..b5110722d5c 100644 --- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/InstallModels.tsx +++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/InstallModels.tsx @@ -1,28 +1,28 @@ import { Box, Flex, Heading, Tab, TabList, TabPanel, TabPanels, Tabs } from '@invoke-ai/ui-library'; +import { useStore } from '@nanostores/react'; import { StarterModelsForm } from 'features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StarterModelsForm'; -import { useMemo } from 'react'; +import { atom } from 'nanostores'; +import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; -import { useMainModels } from 'services/api/hooks/modelsByType'; import { HuggingFaceForm } from './AddModelPanel/HuggingFaceFolder/HuggingFaceForm'; import { InstallModelForm } from './AddModelPanel/InstallModelForm'; import { ModelInstallQueue } from './AddModelPanel/ModelInstallQueue/ModelInstallQueue'; import { ScanModelsForm } from './AddModelPanel/ScanFolder/ScanFolderForm'; +export const $installModelsTab = atom(0); + export const InstallModels = () => { const { t } = useTranslation(); - const [mainModels, { data }] = useMainModels(); - const defaultIndex = useMemo(() => { - if (data && mainModels.length) { - return 0; - } - return 3; - }, [data, mainModels.length]); + const index = useStore($installModelsTab); + const onChange = useCallback((index: number) => { + $installModelsTab.set(index); + }, []); return ( {t('modelManager.addModel')} - + {t('modelManager.urlOrLocalPath')} {t('modelManager.huggingFace')} diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts index 638ebf2fb2f..1516a3fae3b 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts @@ -24,7 +24,7 @@ import { addLoRAs } from './generation/addLoRAs'; import { addSDXLLoRas } from './generation/addSDXLLoRAs'; import { getBoardField, getSDXLStylePrompts } from './graphBuilderUtils'; -export const buildMultidiffusionUpscsaleGraph = async (state: RootState): Promise => { +export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise => { const { model, cfgScale: cfg_scale, scheduler, steps, vaePrecision, seed, vae } = state.generation; const { positivePrompt, negativePrompt } = state.controlLayers.present; const { upscaleModel, upscaleInitialImage, structure, creativity, tileControlnetModel, scale } = state.upscale; @@ -213,7 +213,7 @@ export const buildMultidiffusionUpscsaleGraph = async (state: RootState): Promis control_model: tileControlnetModel, control_mode: 'balanced', resize_mode: 'just_resize', - control_weight: (structure + 10) * 0.0325 + 0.15 + 0.15, + control_weight: (structure + 10) * 0.0325 + 0.3, begin_step_percent: 0, end_step_percent: (structure + 10) * 0.025 + 0.3, }); @@ -226,7 +226,7 @@ export const buildMultidiffusionUpscsaleGraph = async (state: RootState): Promis control_model: tileControlnetModel, control_mode: 'balanced', resize_mode: 'just_resize', - control_weight: ((structure + 10) * 0.0325 + 0.15) * 0.15, + control_weight: ((structure + 10) * 0.0325 + 0.15) * 0.45, begin_step_percent: (structure + 10) * 0.025 + 0.3, end_step_percent: 0.85, }); diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/MultidiffusionWarning.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/MultidiffusionWarning.tsx index 84b8432aec2..f3e2aa66048 100644 --- a/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/MultidiffusionWarning.tsx +++ b/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/MultidiffusionWarning.tsx @@ -1,10 +1,10 @@ -import { Flex, Link, Text } from '@invoke-ai/ui-library'; +import { Button, Flex, ListItem, Text, UnorderedList } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { $installModelsTab } from 'features/modelManagerV2/subpanels/InstallModels'; import { tileControlnetModelChanged } from 'features/parameters/store/upscaleSlice'; -import { MODEL_TYPE_SHORT_MAP } from 'features/parameters/types/constants'; import { setActiveTab } from 'features/ui/store/uiSlice'; import { useCallback, useEffect, useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; +import { Trans, useTranslation } from 'react-i18next'; import { useControlNetModels } from 'services/api/hooks/modelsByType'; export const MultidiffusionWarning = () => { @@ -23,38 +23,46 @@ export const MultidiffusionWarning = () => { dispatch(tileControlnetModelChanged(validModel || null)); }, [model?.base, modelConfigs, dispatch]); - const warningText = useMemo(() => { + const warnings = useMemo(() => { + const _warnings: string[] = []; if (!model) { - return t('upscaling.warningNoMainModel'); + _warnings.push(t('upscaling.mainModelDesc')); } - if (!upscaleModel && !tileControlnetModel) { - return t('upscaling.warningNoTileOrUpscaleModel', { base_model: MODEL_TYPE_SHORT_MAP[model.base] }); + if (!tileControlnetModel) { + _warnings.push(t('upscaling.tileControlNetModelDesc')); } if (!upscaleModel) { - return t('upscaling.warningNoUpscaleModel'); - } - if (!tileControlnetModel) { - return t('upscaling.warningNoTile', { base_model: MODEL_TYPE_SHORT_MAP[model.base] }); + _warnings.push(t('upscaling.upscaleModelDesc')); } + return _warnings; }, [model, upscaleModel, tileControlnetModel, t]); const handleGoToModelManager = useCallback(() => { dispatch(setActiveTab('models')); + $installModelsTab.set(3); }, [dispatch]); - if (!warningText || isLoading || !shouldShowButton) { - return <>; + if (!warnings.length || isLoading || !shouldShowButton) { + return null; } return ( - - - {t('upscaling.visit')}{' '} - - {t('modelManager.modelManager')} - {' '} - {t('upscaling.toInstall')} {warningText}. + + + + ), + }} + /> + + {warnings.map((warning) => ( + {warning} + ))} + ); }; diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleSettingsAccordion.tsx index c7ac339a518..6002b76521d 100644 --- a/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleSettingsAccordion.tsx +++ b/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleSettingsAccordion.tsx @@ -49,14 +49,16 @@ export const UpscaleSettingsAccordion = memo(() => { return ( - - - - - - - + + + + + + + + +