mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-01-15 06:18:03 -05:00
Prettier.
This commit is contained in:
committed by
psychedelicious
parent
188cf37f48
commit
ee4bc49bd4
@@ -815,7 +815,8 @@
|
||||
"inplaceInstall": "In-place install",
|
||||
"inplaceInstallDesc": "Install models without copying the files. When using the model, it will be loaded from its this location. If disabled, the model file(s) will be copied into the Invoke-managed models directory during installation.",
|
||||
"install": "Install",
|
||||
"installAll": "Install All", "installRepo": "Install Repo",
|
||||
"installAll": "Install All",
|
||||
"installRepo": "Install Repo",
|
||||
"ipAdapters": "IP Adapters",
|
||||
"learnMoreAboutSupportedModels": "Learn more about the models we support",
|
||||
"load": "Load",
|
||||
@@ -869,7 +870,8 @@
|
||||
"sigLip": "SigLIP",
|
||||
"spandrelImageToImage": "Image to Image (Spandrel)",
|
||||
"starterBundles": "Starter Bundles",
|
||||
"starterBundleHelpText": "Easily install all models needed to get started with a base model, including a main model, controlnets, IP adapters, and more. Selecting a bundle will skip any models that you already have installed.", "starterModels": "Starter Models",
|
||||
"starterBundleHelpText": "Easily install all models needed to get started with a base model, including a main model, controlnets, IP adapters, and more. Selecting a bundle will skip any models that you already have installed.",
|
||||
"starterModels": "Starter Models",
|
||||
"starterModelsInModelManager": "Starter Models can be found in Model Manager",
|
||||
"launchpadTab": "Launchpad",
|
||||
"launchpad": {
|
||||
@@ -878,7 +880,8 @@
|
||||
"manualInstall": "Manual Installation",
|
||||
"urlDescription": "Install models from a URL or local file path. Perfect for specific models you want to add.",
|
||||
"huggingFaceDescription": "Browse and install models directly from HuggingFace repositories.",
|
||||
"scanFolderDescription": "Scan a local folder to automatically detect and install models.", "recommendedModels": "Recommended Models",
|
||||
"scanFolderDescription": "Scan a local folder to automatically detect and install models.",
|
||||
"recommendedModels": "Recommended Models",
|
||||
"exploreStarter": "Browse all available starter models",
|
||||
"quickStart": "Quick Start Bundles",
|
||||
"bundleDescription": "Each bundle includes essential models for each model family and curated base models to get started",
|
||||
|
||||
@@ -7,7 +7,7 @@ import { flatMap, negate, uniqWith } from 'lodash-es';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiFolderOpenBold, PiLinkBold, PiStarBold } from 'react-icons/pi';
|
||||
import { SiHuggingface } from "react-icons/si";
|
||||
import { SiHuggingface } from 'react-icons/si';
|
||||
import { useGetStarterModelsQuery, useInstallModelMutation } from 'services/api/endpoints/models';
|
||||
|
||||
export const LaunchpadForm = memo(() => {
|
||||
@@ -16,49 +16,52 @@ export const LaunchpadForm = memo(() => {
|
||||
const { getIsInstalled, buildModelInstallArg } = useBuildModelInstallArg();
|
||||
const { data: starterModelsData } = useGetStarterModelsQuery();
|
||||
// Function to install models from a bundle
|
||||
const installBundle = useCallback((bundleName: string) => {
|
||||
if (!starterModelsData?.starter_bundles) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bundle = starterModelsData.starter_bundles[bundleName];
|
||||
if (!bundle) {
|
||||
return;
|
||||
}
|
||||
const installBundle = useCallback(
|
||||
(bundleName: string) => {
|
||||
if (!starterModelsData?.starter_bundles) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Flatten the models and remove duplicates, which is expected as models can have the same dependencies
|
||||
const flattenedModels = flatMap(bundle, flattenStarterModel);
|
||||
const uniqueModels = uniqWith(
|
||||
flattenedModels,
|
||||
(m1, m2) => m1.source === m2.source || (m1.name === m2.name && m1.base === m2.base && m1.type === m2.type)
|
||||
);
|
||||
// We want to install models that are not installed and skip models that are already installed
|
||||
const install = uniqueModels.filter(negate(getIsInstalled)).map(buildModelInstallArg);
|
||||
const skip = uniqueModels.filter(getIsInstalled).map(buildModelInstallArg);
|
||||
const bundle = starterModelsData.starter_bundles[bundleName];
|
||||
if (!bundle) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Flatten the models and remove duplicates, which is expected as models can have the same dependencies
|
||||
const flattenedModels = flatMap(bundle, flattenStarterModel);
|
||||
const uniqueModels = uniqWith(
|
||||
flattenedModels,
|
||||
(m1, m2) => m1.source === m2.source || (m1.name === m2.name && m1.base === m2.base && m1.type === m2.type)
|
||||
);
|
||||
// We want to install models that are not installed and skip models that are already installed
|
||||
const install = uniqueModels.filter(negate(getIsInstalled)).map(buildModelInstallArg);
|
||||
const skip = uniqueModels.filter(getIsInstalled).map(buildModelInstallArg);
|
||||
|
||||
if (install.length === 0) {
|
||||
toast({
|
||||
status: 'info',
|
||||
title: t('modelManager.bundleAlreadyInstalled', { bundleName }),
|
||||
description: t('modelManager.allModelsAlreadyInstalled'),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Install all models in the bundle
|
||||
install.forEach(installModel);
|
||||
|
||||
let description = t('modelManager.installingXModels', { count: install.length });
|
||||
if (skip.length > 1) {
|
||||
description += t('modelManager.skippingXDuplicates', { count: skip.length - 1 });
|
||||
}
|
||||
|
||||
if (install.length === 0) {
|
||||
toast({
|
||||
status: 'info',
|
||||
title: t('modelManager.bundleAlreadyInstalled', { bundleName }),
|
||||
description: t('modelManager.allModelsAlreadyInstalled'),
|
||||
title: t('modelManager.installingBundle'),
|
||||
description,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Install all models in the bundle
|
||||
install.forEach(installModel);
|
||||
|
||||
let description = t('modelManager.installingXModels', { count: install.length });
|
||||
if (skip.length > 1) {
|
||||
description += t('modelManager.skippingXDuplicates', { count: skip.length - 1 });
|
||||
}
|
||||
|
||||
toast({
|
||||
status: 'info',
|
||||
title: t('modelManager.installingBundle'),
|
||||
description,
|
||||
});
|
||||
}, [starterModelsData, getIsInstalled, buildModelInstallArg, installModel, t]);
|
||||
},
|
||||
[starterModelsData, getIsInstalled, buildModelInstallArg, installModel, t]
|
||||
);
|
||||
|
||||
const navigateToUrlTab = useCallback(() => {
|
||||
$installModelsTab.set(1); // URL/Local Path tab (now index 1)
|
||||
@@ -71,7 +74,7 @@ export const LaunchpadForm = memo(() => {
|
||||
const navigateToScanFolderTab = useCallback(() => {
|
||||
$installModelsTab.set(3); // Scan Folder tab (now index 3)
|
||||
}, []);
|
||||
|
||||
|
||||
const navigateToStarterModelsTab = useCallback(() => {
|
||||
$installModelsTab.set(4); // Starter Models tab (now index 4)
|
||||
}, []);
|
||||
@@ -85,90 +88,91 @@ export const LaunchpadForm = memo(() => {
|
||||
|
||||
const handleFluxBundleClick = useCallback(() => {
|
||||
installBundle('flux');
|
||||
}, [installBundle]); return (
|
||||
}, [installBundle]);
|
||||
return (
|
||||
<Flex flexDir="column" height="100%" gap={3}>
|
||||
<ScrollableContent>
|
||||
<Flex flexDir="column" gap={6} p={3}>
|
||||
{/* Welcome Section */}
|
||||
<Box>
|
||||
<Heading size="md" mb={1}>
|
||||
{t('modelManager.launchpad.welcome')}
|
||||
</Heading>
|
||||
<Text color="base.300" fontSize="sm">
|
||||
{t('modelManager.launchpad.description')}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
{/* Manual Installation Options */}
|
||||
<Box>
|
||||
<Heading size="sm" mb={2}>
|
||||
{t('modelManager.launchpad.manualInstall')}
|
||||
</Heading> <Grid templateColumns="repeat(auto-fit, minmax(280px, 1fr))" gap={3}>
|
||||
<LaunchpadCard
|
||||
title={t('modelManager.urlOrLocalPath')}
|
||||
description={t('modelManager.launchpad.urlDescription')}
|
||||
icon={<PiLinkBold size={24} />}
|
||||
onClick={navigateToUrlTab}
|
||||
/>
|
||||
<LaunchpadCard
|
||||
title={t('modelManager.huggingFace')}
|
||||
description={t('modelManager.launchpad.huggingFaceDescription')}
|
||||
icon={<SiHuggingface size={24} />}
|
||||
onClick={navigateToHuggingFaceTab}
|
||||
/>
|
||||
<LaunchpadCard
|
||||
title={t('modelManager.scanFolder')}
|
||||
description={t('modelManager.launchpad.scanFolderDescription')}
|
||||
icon={<PiFolderOpenBold size={24} />}
|
||||
onClick={navigateToScanFolderTab}
|
||||
/>
|
||||
</Grid>
|
||||
</Box> {/* Recommended Section */}
|
||||
<Box>
|
||||
<Heading size="sm" mb={2}>
|
||||
{t('modelManager.launchpad.recommendedModels')}
|
||||
</Heading>
|
||||
<Flex flexDir="column" gap={2}> {/* Starter Model Bundles - More Prominent */}
|
||||
{/* Welcome Section */}
|
||||
<Box>
|
||||
<Heading size="xs" color="base.100" mb={1}>
|
||||
{t('modelManager.launchpad.quickStart')}
|
||||
<Heading size="md" mb={1}>
|
||||
{t('modelManager.launchpad.welcome')}
|
||||
</Heading>
|
||||
<Text fontSize="xs" color="base.300" mb={2}>
|
||||
{t('modelManager.launchpad.bundleDescription')}
|
||||
</Text> <Grid templateColumns="repeat(auto-fit, minmax(180px, 1fr))" gap={2}>
|
||||
<LaunchpadBundleCard
|
||||
title="Stable Diffusion 1.5"
|
||||
onClick={handleSD15BundleClick}
|
||||
<Text color="base.300" fontSize="sm">
|
||||
{t('modelManager.launchpad.description')}
|
||||
</Text>
|
||||
</Box>
|
||||
{/* Manual Installation Options */}
|
||||
<Box>
|
||||
<Heading size="sm" mb={2}>
|
||||
{t('modelManager.launchpad.manualInstall')}
|
||||
</Heading>{' '}
|
||||
<Grid templateColumns="repeat(auto-fit, minmax(280px, 1fr))" gap={3}>
|
||||
<LaunchpadCard
|
||||
title={t('modelManager.urlOrLocalPath')}
|
||||
description={t('modelManager.launchpad.urlDescription')}
|
||||
icon={<PiLinkBold size={24} />}
|
||||
onClick={navigateToUrlTab}
|
||||
/>
|
||||
<LaunchpadBundleCard
|
||||
title="SDXL"
|
||||
onClick={handleSDXLBundleClick}
|
||||
<LaunchpadCard
|
||||
title={t('modelManager.huggingFace')}
|
||||
description={t('modelManager.launchpad.huggingFaceDescription')}
|
||||
icon={<SiHuggingface size={24} />}
|
||||
onClick={navigateToHuggingFaceTab}
|
||||
/>
|
||||
<LaunchpadBundleCard
|
||||
title="FLUX.1 [dev]"
|
||||
onClick={handleFluxBundleClick}
|
||||
<LaunchpadCard
|
||||
title={t('modelManager.scanFolder')}
|
||||
description={t('modelManager.launchpad.scanFolderDescription')}
|
||||
icon={<PiFolderOpenBold size={24} />}
|
||||
onClick={navigateToScanFolderTab}
|
||||
/>
|
||||
</Grid>
|
||||
</Box> {/* Browse All - Simple Link */}
|
||||
<Box pt={1} borderTop="1px solid" borderColor="base.700">
|
||||
<Text fontSize="xs" color="base.400" mb={1}>
|
||||
{t('modelManager.launchpad.browseAll')}
|
||||
</Text>
|
||||
<Button
|
||||
onClick={navigateToStarterModelsTab}
|
||||
variant="link" color="invokeBlue.300"
|
||||
fontSize="sm"
|
||||
fontWeight="medium"
|
||||
p={0}
|
||||
h="auto"
|
||||
leftIcon={<PiStarBold size={16} />}
|
||||
_hover={{
|
||||
color: "invokeBlue.200",
|
||||
textDecoration: "underline"
|
||||
}}
|
||||
>
|
||||
{t('modelManager.launchpad.exploreStarter')}
|
||||
</Button> </Box> </Flex> </Box>
|
||||
</Box>{' '}
|
||||
{/* Recommended Section */}
|
||||
<Box>
|
||||
<Heading size="sm" mb={2}>
|
||||
{t('modelManager.launchpad.recommendedModels')}
|
||||
</Heading>
|
||||
<Flex flexDir="column" gap={2}>
|
||||
{' '}
|
||||
{/* Starter Model Bundles - More Prominent */}
|
||||
<Box>
|
||||
<Heading size="xs" color="base.100" mb={1}>
|
||||
{t('modelManager.launchpad.quickStart')}
|
||||
</Heading>
|
||||
<Text fontSize="xs" color="base.300" mb={2}>
|
||||
{t('modelManager.launchpad.bundleDescription')}
|
||||
</Text>{' '}
|
||||
<Grid templateColumns="repeat(auto-fit, minmax(180px, 1fr))" gap={2}>
|
||||
<LaunchpadBundleCard title="Stable Diffusion 1.5" onClick={handleSD15BundleClick} />
|
||||
<LaunchpadBundleCard title="SDXL" onClick={handleSDXLBundleClick} />
|
||||
<LaunchpadBundleCard title="FLUX.1 [dev]" onClick={handleFluxBundleClick} />
|
||||
</Grid>
|
||||
</Box>{' '}
|
||||
{/* Browse All - Simple Link */}
|
||||
<Box pt={1} borderTop="1px solid" borderColor="base.700">
|
||||
<Text fontSize="xs" color="base.400" mb={1}>
|
||||
{t('modelManager.launchpad.browseAll')}
|
||||
</Text>
|
||||
<Button
|
||||
onClick={navigateToStarterModelsTab}
|
||||
variant="link"
|
||||
color="invokeBlue.300"
|
||||
fontSize="sm"
|
||||
fontWeight="medium"
|
||||
p={0}
|
||||
h="auto"
|
||||
leftIcon={<PiStarBold size={16} />}
|
||||
_hover={{
|
||||
color: 'invokeBlue.200',
|
||||
textDecoration: 'underline',
|
||||
}}
|
||||
>
|
||||
{t('modelManager.launchpad.exploreStarter')}
|
||||
</Button>{' '}
|
||||
</Box>{' '}
|
||||
</Flex>{' '}
|
||||
</Box>
|
||||
</Flex>
|
||||
</ScrollableContent>
|
||||
</Flex>
|
||||
@@ -186,7 +190,8 @@ interface LaunchpadCardProps {
|
||||
}
|
||||
|
||||
const LaunchpadCard = memo(({ title, description, icon, onClick, variant = 'default' }: LaunchpadCardProps) => {
|
||||
return ( <Button
|
||||
return (
|
||||
<Button
|
||||
onClick={onClick}
|
||||
variant="outline"
|
||||
h="auto"
|
||||
@@ -221,9 +226,9 @@ const LaunchpadCard = memo(({ title, description, icon, onClick, variant = 'defa
|
||||
{title}
|
||||
</Heading>
|
||||
</Flex>
|
||||
<Text
|
||||
fontSize="sm"
|
||||
color={variant === 'featured' ? 'invokeBlue.200' : 'base.400'}
|
||||
<Text
|
||||
fontSize="sm"
|
||||
color={variant === 'featured' ? 'invokeBlue.200' : 'base.400'}
|
||||
lineHeight="1.4"
|
||||
flex="1"
|
||||
whiteSpace="normal"
|
||||
@@ -254,19 +259,20 @@ const LaunchpadBundleCard = memo(({ title, onClick }: LaunchpadBundleCardProps)
|
||||
borderColor="invokeBlue.400"
|
||||
bg="invokeBlue.950"
|
||||
_hover={{
|
||||
bg: "invokeBlue.900",
|
||||
borderColor: "invokeBlue.300",
|
||||
transform: "translateY(-2px)",
|
||||
boxShadow: "0 4px 20px rgba(66, 153, 225, 0.15)",
|
||||
bg: 'invokeBlue.900',
|
||||
borderColor: 'invokeBlue.300',
|
||||
transform: 'translateY(-2px)',
|
||||
boxShadow: '0 4px 20px rgba(66, 153, 225, 0.15)',
|
||||
}}
|
||||
_active={{
|
||||
transform: "translateY(0px)",
|
||||
transform: 'translateY(0px)',
|
||||
}}
|
||||
transition="all 0.2s"
|
||||
cursor="pointer"
|
||||
textAlign="center"
|
||||
justifyContent="center"
|
||||
alignItems="center" borderRadius="lg"
|
||||
alignItems="center"
|
||||
borderRadius="lg"
|
||||
whiteSpace="normal"
|
||||
>
|
||||
<Text fontSize="sm" fontWeight="bold" color="invokeBlue.100" noOfLines={1}>
|
||||
|
||||
@@ -30,13 +30,17 @@ export const InstallModels = memo(() => {
|
||||
<Button alignItems="center" variant="link" leftIcon={<PiInfoBold />} onClick={onClickLearnMore}>
|
||||
<Text variant="subtext">{t('modelManager.learnMoreAboutSupportedModels')}</Text>
|
||||
</Button>
|
||||
</Flex> <Tabs variant="collapse" height="50%" display="flex" flexDir="column" index={index} onChange={onChange}> <TabList>
|
||||
</Flex>{' '}
|
||||
<Tabs variant="collapse" height="50%" display="flex" flexDir="column" index={index} onChange={onChange}>
|
||||
{' '}
|
||||
<TabList>
|
||||
<Tab>{t('modelManager.launchpadTab')}</Tab>
|
||||
<Tab>{t('modelManager.urlOrLocalPath')}</Tab>
|
||||
<Tab>{t('modelManager.huggingFace')}</Tab>
|
||||
<Tab>{t('modelManager.scanFolder')}</Tab>
|
||||
<Tab>{t('modelManager.starterModels')}</Tab>
|
||||
</TabList> <TabPanels p={3} height="100%">
|
||||
</TabList>{' '}
|
||||
<TabPanels p={3} height="100%">
|
||||
<TabPanel height="100%">
|
||||
<LaunchpadForm />
|
||||
</TabPanel>
|
||||
|
||||
Reference in New Issue
Block a user