mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
Upscale Workflow Launchpad updates & translation updates
This commit is contained in:
committed by
psychedelicious
parent
a7d413d372
commit
d608a7469e
@@ -2444,6 +2444,12 @@
|
||||
"upscaling": "Upscaling",
|
||||
"upscalingTab": "$t(ui.tabs.upscaling) $t(common.tab)",
|
||||
"gallery": "Gallery"
|
||||
},
|
||||
"launchpad": {
|
||||
"workflowsTitle": "Go deep with Workflows.",
|
||||
"upscalingTitle": "Upscale and add detail.",
|
||||
"canvasTitle": "Edit and refine on Canvas.",
|
||||
"generateTitle": "Generate images from text prompts."
|
||||
}
|
||||
},
|
||||
"system": {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Button, Flex, Grid, Heading, Text } from '@invoke-ai/ui-library';
|
||||
import { useAutoLayoutContext } from 'features/ui/layouts/auto-layout-context';
|
||||
import { WORKSPACE_PANEL_ID } from 'features/ui/layouts/shared';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { InitialStateMainModelPicker } from './InitialStateMainModelPicker';
|
||||
import { LaunchpadAddStyleReference } from './LaunchpadAddStyleReference';
|
||||
@@ -10,6 +11,7 @@ import { LaunchpadGenerateFromTextButton } from './LaunchpadGenerateFromTextButt
|
||||
import { LaunchpadUseALayoutImageButton } from './LaunchpadUseALayoutImageButton';
|
||||
|
||||
export const CanvasLaunchpadPanel = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const ctx = useAutoLayoutContext();
|
||||
const focusCanvas = useCallback(() => {
|
||||
ctx.focusPanel(WORKSPACE_PANEL_ID);
|
||||
@@ -17,7 +19,7 @@ export const CanvasLaunchpadPanel = memo(() => {
|
||||
return (
|
||||
<Flex flexDir="column" h="full" w="full" alignItems="center" gap={2}>
|
||||
<Flex flexDir="column" w="full" gap={4} px={14} maxW={768} pt="20vh">
|
||||
<Heading mb={4}>Edit and refine on Canvas.</Heading>
|
||||
<Heading mb={4}>{t('ui.launchpad.canvasTitle')}</Heading>
|
||||
<Flex flexDir="column" gap={8}>
|
||||
<Grid gridTemplateColumns="1fr 1fr" gap={8}>
|
||||
<InitialStateMainModelPicker />
|
||||
|
||||
@@ -4,10 +4,12 @@ import { InitialStateMainModelPicker } from 'features/controlLayers/components/S
|
||||
import { LaunchpadAddStyleReference } from 'features/controlLayers/components/SimpleSession/LaunchpadAddStyleReference';
|
||||
import { setActiveTab } from 'features/ui/store/uiSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { LaunchpadGenerateFromTextButton } from './LaunchpadGenerateFromTextButton';
|
||||
|
||||
export const GenerateLaunchpadPanel = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const newCanvasSession = useCallback(() => {
|
||||
dispatch(setActiveTab('canvas'));
|
||||
@@ -16,7 +18,7 @@ export const GenerateLaunchpadPanel = memo(() => {
|
||||
return (
|
||||
<Flex flexDir="column" h="full" w="full" alignItems="center" gap={2}>
|
||||
<Flex flexDir="column" w="full" gap={4} px={14} maxW={768} pt="20vh">
|
||||
<Heading mb={4}>Generate images from text prompts.</Heading>
|
||||
<Heading mb={4}>{t('ui.launchpad.generateTitle')}</Heading>
|
||||
<Flex flexDir="column" gap={8}>
|
||||
<Grid gridTemplateColumns="1fr 1fr" gap={8}>
|
||||
<InitialStateMainModelPicker />
|
||||
|
||||
@@ -1,83 +1,150 @@
|
||||
import { Box, Flex, FormControl, FormLabel, Heading, Text } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { Box, Flex, FormControl, FormLabel, Grid, Heading, Icon, Text } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
|
||||
import { setUpscaleInitialImageDndTarget } from 'features/dnd/dnd';
|
||||
import { DndDropTarget } from 'features/dnd/DndDropTarget';
|
||||
import { DndImage } from 'features/dnd/DndImage';
|
||||
import { DndImageIcon } from 'features/dnd/DndImageIcon';
|
||||
import ParamSpandrelModel from 'features/parameters/components/Upscale/ParamSpandrelModel';
|
||||
import { selectUpscaleInitialImage } from 'features/parameters/store/upscaleSlice';
|
||||
import { selectUpscaleInitialImage, upscaleInitialImageChanged } from 'features/parameters/store/upscaleSlice';
|
||||
import { MainModelPicker } from 'features/settingsAccordions/components/GenerationSettingsAccordion/MainModelPicker';
|
||||
import { UpscaleScaleSlider } from 'features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleScaleSlider';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiImageBold } from 'react-icons/pi';
|
||||
import { PiArrowCounterClockwiseBold, PiImageBold, PiUploadBold } from 'react-icons/pi';
|
||||
import type { ImageDTO } from 'services/api/types';
|
||||
|
||||
import { LaunchpadButton } from './LaunchpadButton';
|
||||
|
||||
export const UpscalingLaunchpadPanel = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const upscaleInitialImage = useAppSelector(selectUpscaleInitialImage);
|
||||
|
||||
const onUpload = useCallback(() => {
|
||||
// Upload handler will be called automatically by the upload hook
|
||||
}, []);
|
||||
const dndTargetData = useMemo(() => setUpscaleInitialImageDndTarget.getData(), []);
|
||||
|
||||
const onUpload = useCallback(
|
||||
(imageDTO: ImageDTO) => {
|
||||
dispatch(upscaleInitialImageChanged(imageDTO));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const onReset = useCallback(() => {
|
||||
dispatch(upscaleInitialImageChanged(null));
|
||||
}, [dispatch]);
|
||||
|
||||
const uploadApi = useImageUploadButton({ allowMultiple: false, onUpload });
|
||||
|
||||
return (
|
||||
<Flex flexDir="column" h="full" w="full" alignItems="center" gap={2}>
|
||||
<Flex flexDir="column" w="full" gap={6} px={14} maxW={768} pt="20vh">
|
||||
<Heading mb={4}>{t('upscaling.upscale')} and add detail.</Heading>
|
||||
<Flex flexDir="column" w="full" gap={4} px={14} maxW={768} pt="20vh">
|
||||
<Heading mb={4}>{t('ui.launchpad.upscalingTitle')}</Heading>
|
||||
|
||||
{/* Upload Area - First CTA as per Devon's feedback */}
|
||||
<LaunchpadButton {...uploadApi.getUploadButtonProps()} position="relative" gap={8} h={24}>
|
||||
<Flex flexDir="column" alignItems="center" gap={2}>
|
||||
<PiImageBold size={32} />
|
||||
<Box textAlign="center">
|
||||
{!upscaleInitialImage && (
|
||||
<>
|
||||
<Text fontWeight="semibold">Click or drag an image to upscale</Text>
|
||||
<Text variant="subtext" fontSize="sm">
|
||||
JPG, PNG, WebP up to 100MB
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
{upscaleInitialImage && (
|
||||
<>
|
||||
<Text fontWeight="semibold">Image ready</Text>
|
||||
<Text variant="subtext" fontSize="sm">
|
||||
Press Invoke to begin upscaling
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
</Flex>
|
||||
{/* Upload Area */}
|
||||
<LaunchpadButton {...uploadApi.getUploadButtonProps()} position="relative" gap={8}>
|
||||
{!upscaleInitialImage ? (
|
||||
<>
|
||||
<Icon as={PiImageBold} boxSize={8} color="base.500" />
|
||||
<Flex flexDir="column" alignItems="flex-start" gap={2}>
|
||||
<Heading size="sm">Upload Image to Upscale</Heading>
|
||||
<Text color="base.300">Click or drag an image to upscale (JPG, PNG, WebP up to 100MB)</Text>
|
||||
</Flex>
|
||||
<Flex position="absolute" right={3} bottom={3}>
|
||||
<PiUploadBold />
|
||||
<input {...uploadApi.getUploadInputProps()} />
|
||||
</Flex>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Flex position="relative" w={16} h={16} alignItems="center" justifyContent="center">
|
||||
<DndImage imageDTO={upscaleInitialImage} />
|
||||
<Flex position="absolute" flexDir="column" top={1} insetInlineEnd={1} gap={1}>
|
||||
<DndImageIcon
|
||||
onClick={onReset}
|
||||
icon={<PiArrowCounterClockwiseBold size={12} />}
|
||||
tooltip={t('common.reset')}
|
||||
/>
|
||||
</Flex>
|
||||
<Text
|
||||
position="absolute"
|
||||
background="base.900"
|
||||
color="base.50"
|
||||
fontSize="xs"
|
||||
fontWeight="semibold"
|
||||
bottom={0}
|
||||
left={0}
|
||||
opacity={0.7}
|
||||
px={1}
|
||||
lineHeight={1.25}
|
||||
borderTopEndRadius="base"
|
||||
borderBottomStartRadius="base"
|
||||
pointerEvents="none"
|
||||
>{`${upscaleInitialImage.width}x${upscaleInitialImage.height}`}</Text>
|
||||
</Flex>
|
||||
<Flex flexDir="column" alignItems="flex-start" gap={2}>
|
||||
<Heading size="sm">Image Ready</Heading>
|
||||
<Text color="base.300">Press Invoke to begin upscaling</Text>
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
<DndDropTarget
|
||||
dndTarget={setUpscaleInitialImageDndTarget}
|
||||
dndTargetData={dndTargetData}
|
||||
label={t('gallery.drop')}
|
||||
/>
|
||||
</LaunchpadButton>
|
||||
|
||||
{/* Controls - 60% width as per Devon's feedback */}
|
||||
<Flex flexDir="column" gap={4} w="60%">
|
||||
{/* Upscale Model */}
|
||||
<FormControl>
|
||||
<FormLabel>{t('upscaling.upscaleModel')}</FormLabel>
|
||||
<ParamSpandrelModel />
|
||||
</FormControl>
|
||||
{/* Guidance text */}
|
||||
{upscaleInitialImage && (
|
||||
<Flex
|
||||
bg="base.800"
|
||||
p={4}
|
||||
borderRadius="base"
|
||||
border="1px solid"
|
||||
borderColor="base.700"
|
||||
mt={6}
|
||||
>
|
||||
<Text variant="subtext" fontSize="sm" lineHeight="1.6">
|
||||
<strong>Ready to upscale!</strong> Configure your settings below, then click the <strong>Invoke</strong> button to begin upscaling your image.
|
||||
</Text>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{/* Generation Model */}
|
||||
<FormControl>
|
||||
<FormLabel>{t('parameters.model')}</FormLabel>
|
||||
<MainModelPicker />
|
||||
</FormControl>
|
||||
|
||||
{/* Scale Slider - Same width as dropdowns */}
|
||||
<UpscaleScaleSlider />
|
||||
</Flex>
|
||||
|
||||
{/* Description text with paragraph breaks as per Devon's feedback */}
|
||||
<Box w="full" maxW="40%" ml="auto">
|
||||
<Text variant="subtext" fontSize="sm" lineHeight="1.6">
|
||||
When upscaling, use a prompt that describes the medium and style. Avoid describing specific content details in the image.
|
||||
</Text>
|
||||
<Text variant="subtext" fontSize="sm" lineHeight="1.6" mt={3}>
|
||||
Upscaling works best with the general style of your image.
|
||||
</Text>
|
||||
</Box>
|
||||
{/* Controls */}
|
||||
<style>{`.launchpad-hide-label .chakra-form__label { display: none !important; }`}</style>
|
||||
<Grid gridTemplateColumns="1fr 1fr" gap={10} alignItems="start" mt={upscaleInitialImage ? 8 : 12}>
|
||||
{/* Left Column: All parameters stacked */}
|
||||
<Flex flexDir="column" gap={6} alignItems="flex-start">
|
||||
<Box w="full">
|
||||
<Text fontWeight="semibold" fontSize="sm" mb={1}>Upscale Model</Text>
|
||||
<Box className="launchpad-hide-label">
|
||||
<ParamSpandrelModel />
|
||||
</Box>
|
||||
</Box>
|
||||
<Box w="full">
|
||||
<Text fontWeight="semibold" fontSize="sm" mb={1}>Model</Text>
|
||||
<Box className="launchpad-hide-label">
|
||||
<MainModelPicker />
|
||||
</Box>
|
||||
</Box>
|
||||
<Box w="full">
|
||||
<Text fontWeight="semibold" fontSize="sm" mb={1}>Scale</Text>
|
||||
<Box className="launchpad-hide-label">
|
||||
<UpscaleScaleSlider />
|
||||
</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
{/* Right Column: Description/help text */}
|
||||
<Box>
|
||||
<Text variant="subtext" fontSize="sm" lineHeight="1.6">
|
||||
When upscaling, use a prompt that describes the medium and style. Avoid describing specific content details in the image.
|
||||
</Text>
|
||||
<Text variant="subtext" fontSize="sm" lineHeight="1.6" mt={3}>
|
||||
Upscaling works best with the general style of your image.
|
||||
</Text>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button, Flex, Heading, Link, Text } from '@invoke-ai/ui-library';
|
||||
import { Button, Flex, Heading, Icon, Link, Text } from '@invoke-ai/ui-library';
|
||||
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
|
||||
import { useWorkflowLibraryModal } from 'features/nodes/store/workflowLibraryModal';
|
||||
import { useNewWorkflow } from 'features/workflowLibrary/components/NewWorkflowConfirmationAlertDialog';
|
||||
@@ -53,11 +53,11 @@ export const WorkflowsLaunchpadPanel = memo(() => {
|
||||
|
||||
return (
|
||||
<Flex flexDir="column" h="full" w="full" alignItems="center" gap={2}>
|
||||
<Flex flexDir="column" w="full" gap={6} px={14} maxW={768} pt="20vh">
|
||||
<Heading mb={4}>Go deep with Workflows.</Heading>
|
||||
<Flex flexDir="column" w="full" gap={4} px={14} maxW={768} pt="20vh">
|
||||
<Heading mb={4}>{t('ui.launchpad.workflowsTitle')}</Heading>
|
||||
|
||||
{/* Description */}
|
||||
<Text variant="subtext" fontSize="md" lineHeight="1.6" mb={2}>
|
||||
<Text variant="subtext" fontSize="md" lineHeight="1.6">
|
||||
Workflows are reusable templates that automate image generation tasks,
|
||||
allowing you to quickly perform complex operations and get consistent results.
|
||||
</Text>
|
||||
@@ -67,43 +67,36 @@ export const WorkflowsLaunchpadPanel = memo(() => {
|
||||
isExternal
|
||||
color="invokeBlue.400"
|
||||
fontSize="sm"
|
||||
mb={4}
|
||||
>
|
||||
{t('nodes.learnMore')} about creating workflows
|
||||
{t('learnMore')} about creating workflows
|
||||
</Link>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<Flex flexDir="column" gap={4}>
|
||||
{/* Browse Workflow Templates - Updated copy per Devon's feedback */}
|
||||
<LaunchpadButton onClick={handleBrowseTemplates} gap={4}>
|
||||
<PiFolderOpenBold size={24} />
|
||||
<Flex flexDir="column" alignItems="flex-start" flex={1}>
|
||||
<Text fontWeight="semibold">Browse Workflow Templates</Text>
|
||||
<Text variant="subtext" fontSize="sm">
|
||||
Choose from pre-built workflows for common tasks
|
||||
</Text>
|
||||
<Flex flexDir="column" gap={8}>
|
||||
{/* Browse Workflow Templates */}
|
||||
<LaunchpadButton onClick={handleBrowseTemplates} position="relative" gap={8}>
|
||||
<Icon as={PiFolderOpenBold} boxSize={8} color="base.500" />
|
||||
<Flex flexDir="column" alignItems="flex-start" gap={2}>
|
||||
<Heading size="sm">Browse Workflow Templates</Heading>
|
||||
<Text color="base.300">Choose from pre-built workflows for common tasks</Text>
|
||||
</Flex>
|
||||
</LaunchpadButton>
|
||||
|
||||
{/* Create a new Workflow */}
|
||||
<LaunchpadButton onClick={handleCreateNew} gap={4}>
|
||||
<PiFilePlusBold size={24} />
|
||||
<Flex flexDir="column" alignItems="flex-start" flex={1}>
|
||||
<Text fontWeight="semibold">Create a new Workflow</Text>
|
||||
<Text variant="subtext" fontSize="sm">
|
||||
Start a new workflow from scratch
|
||||
</Text>
|
||||
<LaunchpadButton onClick={handleCreateNew} position="relative" gap={8}>
|
||||
<Icon as={PiFilePlusBold} boxSize={8} color="base.500" />
|
||||
<Flex flexDir="column" alignItems="flex-start" gap={2}>
|
||||
<Heading size="sm">Create a new Workflow</Heading>
|
||||
<Text color="base.300">Start a new workflow from scratch</Text>
|
||||
</Flex>
|
||||
</LaunchpadButton>
|
||||
|
||||
{/* Load workflow from existing image or file - Updated copy per Devon's feedback */}
|
||||
<LaunchpadButton onClick={handleLoadFromFile} gap={4}>
|
||||
<PiUploadBold size={24} />
|
||||
<Flex flexDir="column" alignItems="flex-start" flex={1}>
|
||||
<Text fontWeight="semibold">Load workflow from existing image or file</Text>
|
||||
<Text variant="subtext" fontSize="sm">
|
||||
Drag or upload a workflow to start with an existing setup
|
||||
</Text>
|
||||
{/* Load workflow from existing image or file */}
|
||||
<LaunchpadButton onClick={handleLoadFromFile} position="relative" gap={8}>
|
||||
<Icon as={PiUploadBold} boxSize={8} color="base.500" />
|
||||
<Flex flexDir="column" alignItems="flex-start" gap={2}>
|
||||
<Heading size="sm">Load workflow from existing image or file</Heading>
|
||||
<Text color="base.300">Drag or upload a workflow to start with an existing setup</Text>
|
||||
</Flex>
|
||||
</LaunchpadButton>
|
||||
</Flex>
|
||||
|
||||
Reference in New Issue
Block a user