mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
Improves code structure, comments, formatting, linting
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import {
|
||||
IconButton,
|
||||
useColorModeValue,
|
||||
Flex,
|
||||
Text,
|
||||
Tooltip,
|
||||
IconButton,
|
||||
useColorModeValue,
|
||||
Flex,
|
||||
Text,
|
||||
Tooltip,
|
||||
} from '@chakra-ui/react';
|
||||
import { useAppDispatch, useAppSelector } from '../../app/hooks';
|
||||
import { RootState } from '../../app/store';
|
||||
@@ -14,112 +14,111 @@ import { createSelector } from '@reduxjs/toolkit';
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
const logSelector = createSelector(
|
||||
(state: RootState) => state.system,
|
||||
(system: SystemState) => system.log,
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: (a, b) => a.length === b.length,
|
||||
},
|
||||
}
|
||||
(state: RootState) => state.system,
|
||||
(system: SystemState) => system.log,
|
||||
{
|
||||
memoizeOptions: {
|
||||
// We don't need a deep equality check for this selector.
|
||||
resultEqualityCheck: (a, b) => a.length === b.length,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const systemSelector = createSelector(
|
||||
(state: RootState) => state.system,
|
||||
(system: SystemState) => {
|
||||
return { shouldShowLogViewer: system.shouldShowLogViewer };
|
||||
(state: RootState) => state.system,
|
||||
(system: SystemState) => {
|
||||
return { shouldShowLogViewer: system.shouldShowLogViewer };
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: isEqual,
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: isEqual,
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Basic log viewer, floats on bottom of page.
|
||||
*/
|
||||
const LogViewer = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const bg = useColorModeValue('gray.50', 'gray.900');
|
||||
const borderColor = useColorModeValue('gray.500', 'gray.500');
|
||||
const [shouldAutoscroll, setShouldAutoscroll] = useState<boolean>(true);
|
||||
const dispatch = useAppDispatch();
|
||||
const log = useAppSelector(logSelector);
|
||||
const { shouldShowLogViewer } = useAppSelector(systemSelector);
|
||||
|
||||
const log = useAppSelector(logSelector);
|
||||
const { shouldShowLogViewer } = useAppSelector(systemSelector);
|
||||
const bg = useColorModeValue('gray.50', 'gray.900');
|
||||
const borderColor = useColorModeValue('gray.500', 'gray.500');
|
||||
|
||||
const viewerRef = useRef<HTMLDivElement>(null);
|
||||
// Rudimentary autoscroll
|
||||
const [shouldAutoscroll, setShouldAutoscroll] = useState<boolean>(true);
|
||||
const viewerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (viewerRef.current !== null && shouldAutoscroll) {
|
||||
viewerRef.current.scrollTop = viewerRef.current.scrollHeight;
|
||||
}
|
||||
});
|
||||
useLayoutEffect(() => {
|
||||
if (viewerRef.current !== null && shouldAutoscroll) {
|
||||
viewerRef.current.scrollTop = viewerRef.current.scrollHeight;
|
||||
}
|
||||
}, [shouldAutoscroll]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{shouldShowLogViewer && (
|
||||
<Flex
|
||||
position={'fixed'}
|
||||
left={0}
|
||||
bottom={0}
|
||||
height='200px'
|
||||
width='100vw'
|
||||
overflow='auto'
|
||||
direction='column'
|
||||
fontFamily='monospace'
|
||||
fontSize='sm'
|
||||
pl={12}
|
||||
pr={2}
|
||||
pb={2}
|
||||
borderTopWidth='4px'
|
||||
borderColor={borderColor}
|
||||
background={bg}
|
||||
ref={viewerRef}
|
||||
>
|
||||
{log.map((entry, i) => (
|
||||
<Flex gap={2} key={i}>
|
||||
<Text fontSize='sm' fontWeight={'semibold'}>
|
||||
{entry.timestamp}:
|
||||
</Text>
|
||||
<Text fontSize='sm' wordBreak={'break-all'}>
|
||||
{entry.message}
|
||||
</Text>
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
)}
|
||||
{shouldShowLogViewer && (
|
||||
<Tooltip
|
||||
label={
|
||||
shouldAutoscroll ? 'Autoscroll on' : 'Autoscroll off'
|
||||
}
|
||||
>
|
||||
<IconButton
|
||||
size='sm'
|
||||
position={'fixed'}
|
||||
left={2}
|
||||
bottom={12}
|
||||
aria-label='Toggle autoscroll'
|
||||
variant={'solid'}
|
||||
colorScheme={shouldAutoscroll ? 'blue' : 'gray'}
|
||||
icon={<FaAngleDoubleDown />}
|
||||
onClick={() => setShouldAutoscroll(!shouldAutoscroll)}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip label={shouldShowLogViewer ? 'Hide logs' : 'Show logs'}>
|
||||
<IconButton
|
||||
size='sm'
|
||||
position={'fixed'}
|
||||
left={2}
|
||||
bottom={2}
|
||||
variant={'solid'}
|
||||
aria-label='Toggle Log Viewer'
|
||||
icon={shouldShowLogViewer ? <FaMinus /> : <FaCode />}
|
||||
onClick={() =>
|
||||
dispatch(setShouldShowLogViewer(!shouldShowLogViewer))
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
{shouldShowLogViewer && (
|
||||
<Flex
|
||||
position={'fixed'}
|
||||
left={0}
|
||||
bottom={0}
|
||||
height="200px" // TODO: Make the log viewer resizeable.
|
||||
width="100vw"
|
||||
overflow="auto"
|
||||
direction="column"
|
||||
fontFamily="monospace"
|
||||
fontSize="sm"
|
||||
pl={12}
|
||||
pr={2}
|
||||
pb={2}
|
||||
borderTopWidth="4px"
|
||||
borderColor={borderColor}
|
||||
background={bg}
|
||||
ref={viewerRef}
|
||||
>
|
||||
{log.map((entry, i) => (
|
||||
<Flex gap={2} key={i}>
|
||||
<Text fontSize="sm" fontWeight={'semibold'}>
|
||||
{entry.timestamp}:
|
||||
</Text>
|
||||
<Text fontSize="sm" wordBreak={'break-all'}>
|
||||
{entry.message}
|
||||
</Text>
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
)}
|
||||
{shouldShowLogViewer && (
|
||||
<Tooltip label={shouldAutoscroll ? 'Autoscroll on' : 'Autoscroll off'}>
|
||||
<IconButton
|
||||
size="sm"
|
||||
position={'fixed'}
|
||||
left={2}
|
||||
bottom={12}
|
||||
aria-label="Toggle autoscroll"
|
||||
variant={'solid'}
|
||||
colorScheme={shouldAutoscroll ? 'blue' : 'gray'}
|
||||
icon={<FaAngleDoubleDown />}
|
||||
onClick={() => setShouldAutoscroll(!shouldAutoscroll)}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip label={shouldShowLogViewer ? 'Hide logs' : 'Show logs'}>
|
||||
<IconButton
|
||||
size="sm"
|
||||
position={'fixed'}
|
||||
left={2}
|
||||
bottom={2}
|
||||
variant={'solid'}
|
||||
aria-label="Toggle Log Viewer"
|
||||
icon={shouldShowLogViewer ? <FaMinus /> : <FaCode />}
|
||||
onClick={() => dispatch(setShouldShowLogViewer(!shouldShowLogViewer))}
|
||||
/>
|
||||
</Tooltip>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LogViewer;
|
||||
|
||||
@@ -1,170 +1,164 @@
|
||||
import {
|
||||
Flex,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
Heading,
|
||||
HStack,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
Switch,
|
||||
Text,
|
||||
useDisclosure,
|
||||
Button,
|
||||
Flex,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
Heading,
|
||||
HStack,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
Switch,
|
||||
Text,
|
||||
useDisclosure,
|
||||
} from '@chakra-ui/react';
|
||||
import { useAppDispatch, useAppSelector } from '../../app/hooks';
|
||||
import {
|
||||
setShouldConfirmOnDelete,
|
||||
setShouldDisplayInProgress,
|
||||
SystemState,
|
||||
setShouldConfirmOnDelete,
|
||||
setShouldDisplayInProgress,
|
||||
SystemState,
|
||||
} from './systemSlice';
|
||||
import { RootState } from '../../app/store';
|
||||
import SDButton from '../../components/SDButton';
|
||||
import { persistor } from '../../main';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { isEqual } from 'lodash';
|
||||
import { cloneElement, ReactElement } from 'react';
|
||||
|
||||
const systemSelector = createSelector(
|
||||
(state: RootState) => state.system,
|
||||
(system: SystemState) => {
|
||||
const { shouldDisplayInProgress, shouldConfirmOnDelete } = system;
|
||||
return { shouldDisplayInProgress, shouldConfirmOnDelete };
|
||||
},
|
||||
{
|
||||
memoizeOptions: { resultEqualityCheck: isEqual },
|
||||
}
|
||||
(state: RootState) => state.system,
|
||||
(system: SystemState) => {
|
||||
const { shouldDisplayInProgress, shouldConfirmOnDelete } = system;
|
||||
return { shouldDisplayInProgress, shouldConfirmOnDelete };
|
||||
},
|
||||
{
|
||||
memoizeOptions: { resultEqualityCheck: isEqual },
|
||||
}
|
||||
);
|
||||
|
||||
type Props = {
|
||||
children: ReactElement;
|
||||
type SettingsModalProps = {
|
||||
/* The button to open the Settings Modal */
|
||||
children: ReactElement;
|
||||
};
|
||||
|
||||
const SettingsModal = ({ children }: Props) => {
|
||||
const {
|
||||
isOpen: isSettingsModalOpen,
|
||||
onOpen: onSettingsModalOpen,
|
||||
onClose: onSettingsModalClose,
|
||||
} = useDisclosure();
|
||||
/**
|
||||
* Modal for app settings. Also provides Reset functionality in which the
|
||||
* app's localstorage is wiped via redux-persist.
|
||||
*
|
||||
* Secondary post-reset modal is included here.
|
||||
*/
|
||||
const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
const {
|
||||
isOpen: isSettingsModalOpen,
|
||||
onOpen: onSettingsModalOpen,
|
||||
onClose: onSettingsModalClose,
|
||||
} = useDisclosure();
|
||||
|
||||
const {
|
||||
isOpen: isRefreshModalOpen,
|
||||
onOpen: onRefreshModalOpen,
|
||||
onClose: onRefreshModalClose,
|
||||
} = useDisclosure();
|
||||
const {
|
||||
isOpen: isRefreshModalOpen,
|
||||
onOpen: onRefreshModalOpen,
|
||||
onClose: onRefreshModalClose,
|
||||
} = useDisclosure();
|
||||
|
||||
const { shouldDisplayInProgress, shouldConfirmOnDelete } =
|
||||
useAppSelector(systemSelector);
|
||||
const { shouldDisplayInProgress, shouldConfirmOnDelete } =
|
||||
useAppSelector(systemSelector);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleClickResetWebUI = () => {
|
||||
persistor.purge().then(() => {
|
||||
onSettingsModalClose();
|
||||
onRefreshModalOpen();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Resets localstorage, then opens a secondary modal informing user to
|
||||
* refresh their browser.
|
||||
* */
|
||||
const handleClickResetWebUI = () => {
|
||||
persistor.purge().then(() => {
|
||||
onSettingsModalClose();
|
||||
onRefreshModalOpen();
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{cloneElement(children, {
|
||||
onClick: onSettingsModalOpen,
|
||||
})}
|
||||
return (
|
||||
<>
|
||||
{cloneElement(children, {
|
||||
onClick: onSettingsModalOpen,
|
||||
})}
|
||||
|
||||
<Modal isOpen={isSettingsModalOpen} onClose={onSettingsModalClose}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>Settings</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Flex gap={5} direction='column'>
|
||||
<FormControl>
|
||||
<HStack>
|
||||
<FormLabel marginBottom={1}>
|
||||
Display in-progress images (slower)
|
||||
</FormLabel>
|
||||
<Switch
|
||||
isChecked={shouldDisplayInProgress}
|
||||
onChange={(e) =>
|
||||
dispatch(
|
||||
setShouldDisplayInProgress(
|
||||
e.target.checked
|
||||
)
|
||||
)
|
||||
}
|
||||
/>
|
||||
</HStack>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<HStack>
|
||||
<FormLabel marginBottom={1}>
|
||||
Confirm on delete
|
||||
</FormLabel>
|
||||
<Switch
|
||||
isChecked={shouldConfirmOnDelete}
|
||||
onChange={(e) =>
|
||||
dispatch(
|
||||
setShouldConfirmOnDelete(
|
||||
e.target.checked
|
||||
)
|
||||
)
|
||||
}
|
||||
/>
|
||||
</HStack>
|
||||
</FormControl>
|
||||
<Modal isOpen={isSettingsModalOpen} onClose={onSettingsModalClose}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>Settings</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Flex gap={5} direction="column">
|
||||
<FormControl>
|
||||
<HStack>
|
||||
<FormLabel marginBottom={1}>
|
||||
Display in-progress images (slower)
|
||||
</FormLabel>
|
||||
<Switch
|
||||
isChecked={shouldDisplayInProgress}
|
||||
onChange={(e) =>
|
||||
dispatch(setShouldDisplayInProgress(e.target.checked))
|
||||
}
|
||||
/>
|
||||
</HStack>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<HStack>
|
||||
<FormLabel marginBottom={1}>Confirm on delete</FormLabel>
|
||||
<Switch
|
||||
isChecked={shouldConfirmOnDelete}
|
||||
onChange={(e) =>
|
||||
dispatch(setShouldConfirmOnDelete(e.target.checked))
|
||||
}
|
||||
/>
|
||||
</HStack>
|
||||
</FormControl>
|
||||
|
||||
<Heading size={'md'}>Reset Web UI</Heading>
|
||||
<Text>
|
||||
Resetting the web UI only resets the browser's
|
||||
local cache of your images and remembered
|
||||
settings. It does not delete any images from
|
||||
disk.
|
||||
</Text>
|
||||
<Text>
|
||||
If images aren't showing up in the gallery or
|
||||
something else isn't working, please try
|
||||
resetting before submitting an issue on GitHub.
|
||||
</Text>
|
||||
<SDButton
|
||||
label='Reset Web UI'
|
||||
colorScheme='red'
|
||||
onClick={handleClickResetWebUI}
|
||||
/>
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
<Heading size={'md'}>Reset Web UI</Heading>
|
||||
<Text>
|
||||
Resetting the web UI only resets the browser's local cache of
|
||||
your images and remembered settings. It does not delete any
|
||||
images from disk.
|
||||
</Text>
|
||||
<Text>
|
||||
If images aren't showing up in the gallery or something else
|
||||
isn't working, please try resetting before submitting an issue
|
||||
on GitHub.
|
||||
</Text>
|
||||
<Button colorScheme="red" onClick={handleClickResetWebUI}>
|
||||
Reset Web UI
|
||||
</Button>
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<SDButton
|
||||
label='Close'
|
||||
onClick={onSettingsModalClose}
|
||||
/>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
<ModalFooter>
|
||||
<Button onClick={onSettingsModalClose}>Close</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
closeOnOverlayClick={false}
|
||||
isOpen={isRefreshModalOpen}
|
||||
onClose={onRefreshModalClose}
|
||||
isCentered
|
||||
>
|
||||
<ModalOverlay bg='blackAlpha.300' backdropFilter='blur(40px)' />
|
||||
<ModalContent>
|
||||
<ModalBody pb={6} pt={6}>
|
||||
<Flex justifyContent={'center'}>
|
||||
<Text fontSize={'lg'}>
|
||||
Web UI has been reset. Refresh the page to
|
||||
reload.
|
||||
</Text>
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
<Modal
|
||||
closeOnOverlayClick={false}
|
||||
isOpen={isRefreshModalOpen}
|
||||
onClose={onRefreshModalClose}
|
||||
isCentered
|
||||
>
|
||||
<ModalOverlay bg="blackAlpha.300" backdropFilter="blur(40px)" />
|
||||
<ModalContent>
|
||||
<ModalBody pb={6} pt={6}>
|
||||
<Flex justifyContent={'center'}>
|
||||
<Text fontSize={'lg'}>
|
||||
Web UI has been reset. Refresh the page to reload.
|
||||
</Text>
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsModal;
|
||||
|
||||
@@ -8,101 +8,97 @@ import { validateSeedWeights } from '../sd/util/seedWeightPairs';
|
||||
import { SystemState } from './systemSlice';
|
||||
|
||||
const sdSelector = createSelector(
|
||||
(state: RootState) => state.sd,
|
||||
(sd: SDState) => {
|
||||
return {
|
||||
prompt: sd.prompt,
|
||||
shouldGenerateVariations: sd.shouldGenerateVariations,
|
||||
seedWeights: sd.seedWeights,
|
||||
maskPath: sd.maskPath,
|
||||
initialImagePath: sd.initialImagePath,
|
||||
seed: sd.seed,
|
||||
};
|
||||
(state: RootState) => state.sd,
|
||||
(sd: SDState) => {
|
||||
return {
|
||||
prompt: sd.prompt,
|
||||
shouldGenerateVariations: sd.shouldGenerateVariations,
|
||||
seedWeights: sd.seedWeights,
|
||||
maskPath: sd.maskPath,
|
||||
initialImagePath: sd.initialImagePath,
|
||||
seed: sd.seed,
|
||||
};
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: isEqual,
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: isEqual,
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const systemSelector = createSelector(
|
||||
(state: RootState) => state.system,
|
||||
(system: SystemState) => {
|
||||
return {
|
||||
isProcessing: system.isProcessing,
|
||||
isConnected: system.isConnected,
|
||||
};
|
||||
(state: RootState) => state.system,
|
||||
(system: SystemState) => {
|
||||
return {
|
||||
isProcessing: system.isProcessing,
|
||||
isConnected: system.isConnected,
|
||||
};
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: isEqual,
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: isEqual,
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/*
|
||||
Checks relevant pieces of state to confirm generation will not deterministically fail.
|
||||
/**
|
||||
* Checks relevant pieces of state to confirm generation will not deterministically fail.
|
||||
* This is used to prevent the 'Generate' button from being clicked.
|
||||
*/
|
||||
const useCheckParameters = (): boolean => {
|
||||
const {
|
||||
prompt,
|
||||
shouldGenerateVariations,
|
||||
seedWeights,
|
||||
maskPath,
|
||||
initialImagePath,
|
||||
seed,
|
||||
} = useAppSelector(sdSelector);
|
||||
|
||||
This is used to prevent the 'Generate' button from being clicked.
|
||||
const { isProcessing, isConnected } = useAppSelector(systemSelector);
|
||||
|
||||
Other parameter values may cause failure but we rely on input validation for those.
|
||||
*/
|
||||
const useCheckParameters = () => {
|
||||
const {
|
||||
prompt,
|
||||
shouldGenerateVariations,
|
||||
seedWeights,
|
||||
maskPath,
|
||||
initialImagePath,
|
||||
seed,
|
||||
} = useAppSelector(sdSelector);
|
||||
return useMemo(() => {
|
||||
// Cannot generate without a prompt
|
||||
if (!prompt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { isProcessing, isConnected } = useAppSelector(systemSelector);
|
||||
// Cannot generate with a mask without img2img
|
||||
if (maskPath && !initialImagePath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return useMemo(() => {
|
||||
// Cannot generate without a prompt
|
||||
if (!prompt) {
|
||||
return false;
|
||||
}
|
||||
// TODO: job queue
|
||||
// Cannot generate if already processing an image
|
||||
if (isProcessing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cannot generate with a mask without img2img
|
||||
if (maskPath && !initialImagePath) {
|
||||
return false;
|
||||
}
|
||||
// Cannot generate if not connected
|
||||
if (!isConnected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: job queue
|
||||
// Cannot generate if already processing an image
|
||||
if (isProcessing) {
|
||||
return false;
|
||||
}
|
||||
// Cannot generate variations without valid seed weights
|
||||
if (
|
||||
shouldGenerateVariations &&
|
||||
(!(validateSeedWeights(seedWeights) || seedWeights === '') || seed === -1)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cannot generate if not connected
|
||||
if (!isConnected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cannot generate variations without valid seed weights
|
||||
if (
|
||||
shouldGenerateVariations &&
|
||||
(!(validateSeedWeights(seedWeights) || seedWeights === '') ||
|
||||
seed === -1)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// All good
|
||||
return true;
|
||||
}, [
|
||||
prompt,
|
||||
maskPath,
|
||||
initialImagePath,
|
||||
isProcessing,
|
||||
isConnected,
|
||||
shouldGenerateVariations,
|
||||
seedWeights,
|
||||
seed,
|
||||
]);
|
||||
// All good
|
||||
return true;
|
||||
}, [
|
||||
prompt,
|
||||
maskPath,
|
||||
initialImagePath,
|
||||
isProcessing,
|
||||
isConnected,
|
||||
shouldGenerateVariations,
|
||||
seedWeights,
|
||||
seed,
|
||||
]);
|
||||
};
|
||||
|
||||
export default useCheckParameters;
|
||||
|
||||
Reference in New Issue
Block a user