mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge branch 'main' into refactor/model_manager_instantiate
This commit is contained in:
commit
02d2cc758d
13
.github/workflows/style-checks.yml
vendored
13
.github/workflows/style-checks.yml
vendored
@ -1,13 +1,15 @@
|
|||||||
name: Black # TODO: add isort and flake8 later
|
name: style checks
|
||||||
|
# just formatting for now
|
||||||
|
# TODO: add isort and flake8 later
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request: {}
|
pull_request:
|
||||||
push:
|
push:
|
||||||
branches: master
|
branches: main
|
||||||
tags: "*"
|
tags: "*"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
black:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@ -19,8 +21,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install dependencies with pip
|
- name: Install dependencies with pip
|
||||||
run: |
|
run: |
|
||||||
pip install --upgrade pip wheel
|
pip install black
|
||||||
pip install .[test]
|
|
||||||
|
|
||||||
# - run: isort --check-only .
|
# - run: isort --check-only .
|
||||||
- run: black --check .
|
- run: black --check .
|
||||||
|
@ -274,7 +274,7 @@ class InvokeAISettings(BaseSettings):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def _excluded(self) -> List[str]:
|
def _excluded(self) -> List[str]:
|
||||||
# internal fields that shouldn't be exposed as command line options
|
# internal fields that shouldn't be exposed as command line options
|
||||||
return ["type", "initconf", "cached_root"]
|
return ["type", "initconf"]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _excluded_from_yaml(self) -> List[str]:
|
def _excluded_from_yaml(self) -> List[str]:
|
||||||
@ -290,7 +290,6 @@ class InvokeAISettings(BaseSettings):
|
|||||||
"restore",
|
"restore",
|
||||||
"root",
|
"root",
|
||||||
"nsfw_checker",
|
"nsfw_checker",
|
||||||
"cached_root",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
@ -356,7 +355,7 @@ class InvokeAISettings(BaseSettings):
|
|||||||
def _find_root() -> Path:
|
def _find_root() -> Path:
|
||||||
venv = Path(os.environ.get("VIRTUAL_ENV") or ".")
|
venv = Path(os.environ.get("VIRTUAL_ENV") or ".")
|
||||||
if os.environ.get("INVOKEAI_ROOT"):
|
if os.environ.get("INVOKEAI_ROOT"):
|
||||||
root = Path(os.environ.get("INVOKEAI_ROOT")).resolve()
|
root = Path(os.environ["INVOKEAI_ROOT"])
|
||||||
elif any([(venv.parent / x).exists() for x in [INIT_FILE, LEGACY_INIT_FILE]]):
|
elif any([(venv.parent / x).exists() for x in [INIT_FILE, LEGACY_INIT_FILE]]):
|
||||||
root = (venv.parent).resolve()
|
root = (venv.parent).resolve()
|
||||||
else:
|
else:
|
||||||
@ -403,7 +402,7 @@ class InvokeAIAppConfig(InvokeAISettings):
|
|||||||
xformers_enabled : bool = Field(default=True, description="Enable/disable memory-efficient attention", category='Memory/Performance')
|
xformers_enabled : bool = Field(default=True, description="Enable/disable memory-efficient attention", category='Memory/Performance')
|
||||||
tiled_decode : bool = Field(default=False, description="Whether to enable tiled VAE decode (reduces memory consumption with some performance penalty)", category='Memory/Performance')
|
tiled_decode : bool = Field(default=False, description="Whether to enable tiled VAE decode (reduces memory consumption with some performance penalty)", category='Memory/Performance')
|
||||||
|
|
||||||
root : Path = Field(default=_find_root(), description='InvokeAI runtime root directory', category='Paths')
|
root : Path = Field(default=None, description='InvokeAI runtime root directory', category='Paths')
|
||||||
autoimport_dir : Path = Field(default='autoimport', description='Path to a directory of models files to be imported on startup.', category='Paths')
|
autoimport_dir : Path = Field(default='autoimport', description='Path to a directory of models files to be imported on startup.', category='Paths')
|
||||||
lora_dir : Path = Field(default=None, description='Path to a directory of LoRA/LyCORIS models to be imported on startup.', category='Paths')
|
lora_dir : Path = Field(default=None, description='Path to a directory of LoRA/LyCORIS models to be imported on startup.', category='Paths')
|
||||||
embedding_dir : Path = Field(default=None, description='Path to a directory of Textual Inversion embeddings to be imported on startup.', category='Paths')
|
embedding_dir : Path = Field(default=None, description='Path to a directory of Textual Inversion embeddings to be imported on startup.', category='Paths')
|
||||||
@ -424,7 +423,6 @@ class InvokeAIAppConfig(InvokeAISettings):
|
|||||||
log_level : Literal[tuple(["debug","info","warning","error","critical"])] = Field(default="info", description="Emit logging messages at this level or higher", category="Logging")
|
log_level : Literal[tuple(["debug","info","warning","error","critical"])] = Field(default="info", description="Emit logging messages at this level or higher", category="Logging")
|
||||||
|
|
||||||
version : bool = Field(default=False, description="Show InvokeAI version and exit", category="Other")
|
version : bool = Field(default=False, description="Show InvokeAI version and exit", category="Other")
|
||||||
cached_root : Path = Field(default=None, description="internal use only", category="DEPRECATED")
|
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
def parse_args(self, argv: List[str] = None, conf: DictConfig = None, clobber=False):
|
def parse_args(self, argv: List[str] = None, conf: DictConfig = None, clobber=False):
|
||||||
@ -472,15 +470,12 @@ class InvokeAIAppConfig(InvokeAISettings):
|
|||||||
"""
|
"""
|
||||||
Path to the runtime root directory
|
Path to the runtime root directory
|
||||||
"""
|
"""
|
||||||
# we cache value of root to protect against it being '.' and the cwd changing
|
if self.root:
|
||||||
if self.cached_root:
|
|
||||||
root = self.cached_root
|
|
||||||
elif self.root:
|
|
||||||
root = Path(self.root).expanduser().absolute()
|
root = Path(self.root).expanduser().absolute()
|
||||||
else:
|
else:
|
||||||
root = self.find_root()
|
root = self.find_root().expanduser().absolute()
|
||||||
self.cached_root = root
|
self.root = root # insulate ourselves from relative paths that may change
|
||||||
return self.cached_root
|
return root
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def root_dir(self) -> Path:
|
def root_dir(self) -> Path:
|
||||||
|
@ -78,10 +78,9 @@ class InvokeAIDiffuserComponent:
|
|||||||
self.cross_attention_control_context = None
|
self.cross_attention_control_context = None
|
||||||
self.sequential_guidance = config.sequential_guidance
|
self.sequential_guidance = config.sequential_guidance
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def custom_attention_context(
|
def custom_attention_context(
|
||||||
cls,
|
self,
|
||||||
unet: UNet2DConditionModel, # note: also may futz with the text encoder depending on requested LoRAs
|
unet: UNet2DConditionModel, # note: also may futz with the text encoder depending on requested LoRAs
|
||||||
extra_conditioning_info: Optional[ExtraConditioningInfo],
|
extra_conditioning_info: Optional[ExtraConditioningInfo],
|
||||||
step_count: int,
|
step_count: int,
|
||||||
@ -91,18 +90,19 @@ class InvokeAIDiffuserComponent:
|
|||||||
old_attn_processors = unet.attn_processors
|
old_attn_processors = unet.attn_processors
|
||||||
# Load lora conditions into the model
|
# Load lora conditions into the model
|
||||||
if extra_conditioning_info.wants_cross_attention_control:
|
if extra_conditioning_info.wants_cross_attention_control:
|
||||||
cross_attention_control_context = Context(
|
self.cross_attention_control_context = Context(
|
||||||
arguments=extra_conditioning_info.cross_attention_control_args,
|
arguments=extra_conditioning_info.cross_attention_control_args,
|
||||||
step_count=step_count,
|
step_count=step_count,
|
||||||
)
|
)
|
||||||
setup_cross_attention_control_attention_processors(
|
setup_cross_attention_control_attention_processors(
|
||||||
unet,
|
unet,
|
||||||
cross_attention_control_context,
|
self.cross_attention_control_context,
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
yield None
|
yield None
|
||||||
finally:
|
finally:
|
||||||
|
self.cross_attention_control_context = None
|
||||||
if old_attn_processors is not None:
|
if old_attn_processors is not None:
|
||||||
unet.set_attn_processor(old_attn_processors)
|
unet.set_attn_processor(old_attn_processors)
|
||||||
# TODO resuscitate attention map saving
|
# TODO resuscitate attention map saving
|
||||||
|
@ -124,7 +124,8 @@
|
|||||||
"deleteImageBin": "Deleted images will be sent to your operating system's Bin.",
|
"deleteImageBin": "Deleted images will be sent to your operating system's Bin.",
|
||||||
"deleteImagePermanent": "Deleted images cannot be restored.",
|
"deleteImagePermanent": "Deleted images cannot be restored.",
|
||||||
"images": "Images",
|
"images": "Images",
|
||||||
"assets": "Assets"
|
"assets": "Assets",
|
||||||
|
"autoAssignBoardOnClick": "Auto-Assign Board on Click"
|
||||||
},
|
},
|
||||||
"hotkeys": {
|
"hotkeys": {
|
||||||
"keyboardShortcuts": "Keyboard Shortcuts",
|
"keyboardShortcuts": "Keyboard Shortcuts",
|
||||||
|
@ -11,11 +11,14 @@ import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
|
|||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[stateSelector],
|
[stateSelector],
|
||||||
({ gallery }) => {
|
({ gallery, system }) => {
|
||||||
const { autoAddBoardId } = gallery;
|
const { autoAddBoardId, autoAssignBoardOnClick } = gallery;
|
||||||
|
const { isProcessing } = system;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
autoAddBoardId,
|
autoAddBoardId,
|
||||||
|
autoAssignBoardOnClick,
|
||||||
|
isProcessing,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
defaultSelectorOptions
|
defaultSelectorOptions
|
||||||
@ -23,7 +26,8 @@ const selector = createSelector(
|
|||||||
|
|
||||||
const BoardAutoAddSelect = () => {
|
const BoardAutoAddSelect = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { autoAddBoardId } = useAppSelector(selector);
|
const { autoAddBoardId, autoAssignBoardOnClick, isProcessing } =
|
||||||
|
useAppSelector(selector);
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
const { boards, hasBoards } = useListAllBoardsQuery(undefined, {
|
const { boards, hasBoards } = useListAllBoardsQuery(undefined, {
|
||||||
selectFromResult: ({ data }) => {
|
selectFromResult: ({ data }) => {
|
||||||
@ -67,7 +71,7 @@ const BoardAutoAddSelect = () => {
|
|||||||
data={boards}
|
data={boards}
|
||||||
nothingFound="No matching Boards"
|
nothingFound="No matching Boards"
|
||||||
itemComponent={IAIMantineSelectItemWithTooltip}
|
itemComponent={IAIMantineSelectItemWithTooltip}
|
||||||
disabled={!hasBoards}
|
disabled={!hasBoards || autoAssignBoardOnClick || isProcessing}
|
||||||
filter={(value, item: SelectItem) =>
|
filter={(value, item: SelectItem) =>
|
||||||
item.label?.toLowerCase().includes(value.toLowerCase().trim()) ||
|
item.label?.toLowerCase().includes(value.toLowerCase().trim()) ||
|
||||||
item.value.toLowerCase().includes(value.toLowerCase().trim())
|
item.value.toLowerCase().includes(value.toLowerCase().trim())
|
||||||
|
@ -25,14 +25,17 @@ const BoardContextMenu = memo(
|
|||||||
|
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createSelector(stateSelector, ({ gallery }) => {
|
createSelector(stateSelector, ({ gallery, system }) => {
|
||||||
const isAutoAdd = gallery.autoAddBoardId === board_id;
|
const isAutoAdd = gallery.autoAddBoardId === board_id;
|
||||||
return { isAutoAdd };
|
const isProcessing = system.isProcessing;
|
||||||
|
const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;
|
||||||
|
return { isAutoAdd, isProcessing, autoAssignBoardOnClick };
|
||||||
}),
|
}),
|
||||||
[board_id]
|
[board_id]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { isAutoAdd } = useAppSelector(selector);
|
const { isAutoAdd, isProcessing, autoAssignBoardOnClick } =
|
||||||
|
useAppSelector(selector);
|
||||||
const boardName = useBoardName(board_id);
|
const boardName = useBoardName(board_id);
|
||||||
|
|
||||||
const handleSetAutoAdd = useCallback(() => {
|
const handleSetAutoAdd = useCallback(() => {
|
||||||
@ -59,7 +62,7 @@ const BoardContextMenu = memo(
|
|||||||
<MenuGroup title={boardName}>
|
<MenuGroup title={boardName}>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon={<FaPlus />}
|
icon={<FaPlus />}
|
||||||
isDisabled={isAutoAdd}
|
isDisabled={isAutoAdd || isProcessing || autoAssignBoardOnClick}
|
||||||
onClick={handleSetAutoAdd}
|
onClick={handleSetAutoAdd}
|
||||||
>
|
>
|
||||||
Auto-add to this Board
|
Auto-add to this Board
|
||||||
|
@ -16,7 +16,10 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAIDroppable from 'common/components/IAIDroppable';
|
import IAIDroppable from 'common/components/IAIDroppable';
|
||||||
import SelectionOverlay from 'common/components/SelectionOverlay';
|
import SelectionOverlay from 'common/components/SelectionOverlay';
|
||||||
import { boardIdSelected } from 'features/gallery/store/gallerySlice';
|
import {
|
||||||
|
autoAddBoardIdChanged,
|
||||||
|
boardIdSelected,
|
||||||
|
} from 'features/gallery/store/gallerySlice';
|
||||||
import { memo, useCallback, useMemo, useState } from 'react';
|
import { memo, useCallback, useMemo, useState } from 'react';
|
||||||
import { FaUser } from 'react-icons/fa';
|
import { FaUser } from 'react-icons/fa';
|
||||||
import { useUpdateBoardMutation } from 'services/api/endpoints/boards';
|
import { useUpdateBoardMutation } from 'services/api/endpoints/boards';
|
||||||
@ -38,18 +41,25 @@ const GalleryBoard = memo(
|
|||||||
() =>
|
() =>
|
||||||
createSelector(
|
createSelector(
|
||||||
stateSelector,
|
stateSelector,
|
||||||
({ gallery }) => {
|
({ gallery, system }) => {
|
||||||
const isSelectedForAutoAdd =
|
const isSelectedForAutoAdd =
|
||||||
board.board_id === gallery.autoAddBoardId;
|
board.board_id === gallery.autoAddBoardId;
|
||||||
|
const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;
|
||||||
|
const isProcessing = system.isProcessing;
|
||||||
|
|
||||||
return { isSelectedForAutoAdd };
|
return {
|
||||||
|
isSelectedForAutoAdd,
|
||||||
|
autoAssignBoardOnClick,
|
||||||
|
isProcessing,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
defaultSelectorOptions
|
defaultSelectorOptions
|
||||||
),
|
),
|
||||||
[board.board_id]
|
[board.board_id]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { isSelectedForAutoAdd } = useAppSelector(selector);
|
const { isSelectedForAutoAdd, autoAssignBoardOnClick, isProcessing } =
|
||||||
|
useAppSelector(selector);
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
const handleMouseOver = useCallback(() => {
|
const handleMouseOver = useCallback(() => {
|
||||||
setIsHovered(true);
|
setIsHovered(true);
|
||||||
@ -66,7 +76,10 @@ const GalleryBoard = memo(
|
|||||||
|
|
||||||
const handleSelectBoard = useCallback(() => {
|
const handleSelectBoard = useCallback(() => {
|
||||||
dispatch(boardIdSelected(board_id));
|
dispatch(boardIdSelected(board_id));
|
||||||
}, [board_id, dispatch]);
|
if (autoAssignBoardOnClick && !isProcessing) {
|
||||||
|
dispatch(autoAddBoardIdChanged(board_id));
|
||||||
|
}
|
||||||
|
}, [board_id, autoAssignBoardOnClick, isProcessing, dispatch]);
|
||||||
|
|
||||||
const [updateBoard, { isLoading: isUpdateBoardLoading }] =
|
const [updateBoard, { isLoading: isUpdateBoardLoading }] =
|
||||||
useUpdateBoardMutation();
|
useUpdateBoardMutation();
|
||||||
|
@ -7,7 +7,10 @@ import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|||||||
import InvokeAILogoImage from 'assets/images/logo.png';
|
import InvokeAILogoImage from 'assets/images/logo.png';
|
||||||
import IAIDroppable from 'common/components/IAIDroppable';
|
import IAIDroppable from 'common/components/IAIDroppable';
|
||||||
import SelectionOverlay from 'common/components/SelectionOverlay';
|
import SelectionOverlay from 'common/components/SelectionOverlay';
|
||||||
import { boardIdSelected } from 'features/gallery/store/gallerySlice';
|
import {
|
||||||
|
boardIdSelected,
|
||||||
|
autoAddBoardIdChanged,
|
||||||
|
} from 'features/gallery/store/gallerySlice';
|
||||||
import { memo, useCallback, useMemo, useState } from 'react';
|
import { memo, useCallback, useMemo, useState } from 'react';
|
||||||
import { useBoardName } from 'services/api/hooks/useBoardName';
|
import { useBoardName } from 'services/api/hooks/useBoardName';
|
||||||
import AutoAddIcon from '../AutoAddIcon';
|
import AutoAddIcon from '../AutoAddIcon';
|
||||||
@ -18,20 +21,25 @@ interface Props {
|
|||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
stateSelector,
|
stateSelector,
|
||||||
({ gallery }) => {
|
({ gallery, system }) => {
|
||||||
const { autoAddBoardId } = gallery;
|
const { autoAddBoardId, autoAssignBoardOnClick } = gallery;
|
||||||
return { autoAddBoardId };
|
const { isProcessing } = system;
|
||||||
|
return { autoAddBoardId, autoAssignBoardOnClick, isProcessing };
|
||||||
},
|
},
|
||||||
defaultSelectorOptions
|
defaultSelectorOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
const NoBoardBoard = memo(({ isSelected }: Props) => {
|
const NoBoardBoard = memo(({ isSelected }: Props) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { autoAddBoardId } = useAppSelector(selector);
|
const { autoAddBoardId, autoAssignBoardOnClick, isProcessing } =
|
||||||
|
useAppSelector(selector);
|
||||||
const boardName = useBoardName(undefined);
|
const boardName = useBoardName(undefined);
|
||||||
const handleSelectBoard = useCallback(() => {
|
const handleSelectBoard = useCallback(() => {
|
||||||
dispatch(boardIdSelected(undefined));
|
dispatch(boardIdSelected(undefined));
|
||||||
}, [dispatch]);
|
if (autoAssignBoardOnClick && !isProcessing) {
|
||||||
|
dispatch(autoAddBoardIdChanged(undefined));
|
||||||
|
}
|
||||||
|
}, [dispatch, autoAssignBoardOnClick, isProcessing]);
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
const handleMouseOver = useCallback(() => {
|
const handleMouseOver = useCallback(() => {
|
||||||
setIsHovered(true);
|
setIsHovered(true);
|
||||||
|
@ -8,6 +8,7 @@ import IAIPopover from 'common/components/IAIPopover';
|
|||||||
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
||||||
import IAISlider from 'common/components/IAISlider';
|
import IAISlider from 'common/components/IAISlider';
|
||||||
import {
|
import {
|
||||||
|
autoAssignBoardOnClickChanged,
|
||||||
setGalleryImageMinimumWidth,
|
setGalleryImageMinimumWidth,
|
||||||
shouldAutoSwitchChanged,
|
shouldAutoSwitchChanged,
|
||||||
} from 'features/gallery/store/gallerySlice';
|
} from 'features/gallery/store/gallerySlice';
|
||||||
@ -19,11 +20,16 @@ import BoardAutoAddSelect from './Boards/BoardAutoAddSelect';
|
|||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[stateSelector],
|
[stateSelector],
|
||||||
(state) => {
|
(state) => {
|
||||||
const { galleryImageMinimumWidth, shouldAutoSwitch } = state.gallery;
|
const {
|
||||||
|
galleryImageMinimumWidth,
|
||||||
|
shouldAutoSwitch,
|
||||||
|
autoAssignBoardOnClick,
|
||||||
|
} = state.gallery;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
galleryImageMinimumWidth,
|
galleryImageMinimumWidth,
|
||||||
shouldAutoSwitch,
|
shouldAutoSwitch,
|
||||||
|
autoAssignBoardOnClick,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
defaultSelectorOptions
|
defaultSelectorOptions
|
||||||
@ -33,7 +39,7 @@ const GallerySettingsPopover = () => {
|
|||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { galleryImageMinimumWidth, shouldAutoSwitch } =
|
const { galleryImageMinimumWidth, shouldAutoSwitch, autoAssignBoardOnClick } =
|
||||||
useAppSelector(selector);
|
useAppSelector(selector);
|
||||||
|
|
||||||
const handleChangeGalleryImageMinimumWidth = (v: number) => {
|
const handleChangeGalleryImageMinimumWidth = (v: number) => {
|
||||||
@ -69,6 +75,13 @@ const GallerySettingsPopover = () => {
|
|||||||
dispatch(shouldAutoSwitchChanged(e.target.checked))
|
dispatch(shouldAutoSwitchChanged(e.target.checked))
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<IAISimpleCheckbox
|
||||||
|
label={t('gallery.autoAssignBoardOnClick')}
|
||||||
|
isChecked={autoAssignBoardOnClick}
|
||||||
|
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||||
|
dispatch(autoAssignBoardOnClickChanged(e.target.checked))
|
||||||
|
}
|
||||||
|
/>
|
||||||
<BoardAutoAddSelect />
|
<BoardAutoAddSelect />
|
||||||
</Flex>
|
</Flex>
|
||||||
</IAIPopover>
|
</IAIPopover>
|
||||||
|
@ -8,6 +8,7 @@ export const initialGalleryState: GalleryState = {
|
|||||||
selection: [],
|
selection: [],
|
||||||
shouldAutoSwitch: true,
|
shouldAutoSwitch: true,
|
||||||
autoAddBoardId: undefined,
|
autoAddBoardId: undefined,
|
||||||
|
autoAssignBoardOnClick: true,
|
||||||
galleryImageMinimumWidth: 96,
|
galleryImageMinimumWidth: 96,
|
||||||
selectedBoardId: undefined,
|
selectedBoardId: undefined,
|
||||||
galleryView: 'images',
|
galleryView: 'images',
|
||||||
@ -66,6 +67,9 @@ export const gallerySlice = createSlice({
|
|||||||
setGalleryImageMinimumWidth: (state, action: PayloadAction<number>) => {
|
setGalleryImageMinimumWidth: (state, action: PayloadAction<number>) => {
|
||||||
state.galleryImageMinimumWidth = action.payload;
|
state.galleryImageMinimumWidth = action.payload;
|
||||||
},
|
},
|
||||||
|
autoAssignBoardOnClickChanged: (state, action: PayloadAction<boolean>) => {
|
||||||
|
state.autoAssignBoardOnClick = action.payload;
|
||||||
|
},
|
||||||
boardIdSelected: (state, action: PayloadAction<BoardId>) => {
|
boardIdSelected: (state, action: PayloadAction<BoardId>) => {
|
||||||
state.selectedBoardId = action.payload;
|
state.selectedBoardId = action.payload;
|
||||||
state.galleryView = 'images';
|
state.galleryView = 'images';
|
||||||
@ -140,6 +144,7 @@ export const {
|
|||||||
imageSelectionToggled,
|
imageSelectionToggled,
|
||||||
imageSelected,
|
imageSelected,
|
||||||
shouldAutoSwitchChanged,
|
shouldAutoSwitchChanged,
|
||||||
|
autoAssignBoardOnClickChanged,
|
||||||
setGalleryImageMinimumWidth,
|
setGalleryImageMinimumWidth,
|
||||||
boardIdSelected,
|
boardIdSelected,
|
||||||
isBatchEnabledChanged,
|
isBatchEnabledChanged,
|
||||||
|
@ -18,6 +18,7 @@ export type GalleryState = {
|
|||||||
selection: string[];
|
selection: string[];
|
||||||
shouldAutoSwitch: boolean;
|
shouldAutoSwitch: boolean;
|
||||||
autoAddBoardId: string | undefined;
|
autoAddBoardId: string | undefined;
|
||||||
|
autoAssignBoardOnClick: boolean;
|
||||||
galleryImageMinimumWidth: number;
|
galleryImageMinimumWidth: number;
|
||||||
selectedBoardId: BoardId;
|
selectedBoardId: BoardId;
|
||||||
galleryView: GalleryView;
|
galleryView: GalleryView;
|
||||||
|
162
shell.nix
162
shell.nix
@ -1,162 +0,0 @@
|
|||||||
{ pkgs ? import <nixpkgs> {}
|
|
||||||
, lib ? pkgs.lib
|
|
||||||
, stdenv ? pkgs.stdenv
|
|
||||||
, fetchurl ? pkgs.fetchurl
|
|
||||||
, runCommand ? pkgs.runCommand
|
|
||||||
, makeWrapper ? pkgs.makeWrapper
|
|
||||||
, mkShell ? pkgs.mkShell
|
|
||||||
, buildFHSUserEnv ? pkgs.buildFHSUserEnv
|
|
||||||
, frameworks ? pkgs.darwin.apple_sdk.frameworks
|
|
||||||
}:
|
|
||||||
|
|
||||||
# Setup InvokeAI environment using nix
|
|
||||||
# Simple usage:
|
|
||||||
# nix-shell
|
|
||||||
# python3 scripts/preload_models.py
|
|
||||||
# python3 scripts/invoke.py -h
|
|
||||||
|
|
||||||
let
|
|
||||||
conda-shell = { url, sha256, installPath, packages, shellHook }:
|
|
||||||
let
|
|
||||||
src = fetchurl { inherit url sha256; };
|
|
||||||
libPath = lib.makeLibraryPath ([] ++ lib.optionals (stdenv.isLinux) [ pkgs.zlib ]);
|
|
||||||
condaArch = if stdenv.system == "aarch64-darwin" then "osx-arm64" else "";
|
|
||||||
installer =
|
|
||||||
if stdenv.isDarwin then
|
|
||||||
runCommand "conda-install" {
|
|
||||||
nativeBuildInputs = [ makeWrapper ];
|
|
||||||
} ''
|
|
||||||
mkdir -p $out/bin
|
|
||||||
cp ${src} $out/bin/miniconda-installer.sh
|
|
||||||
chmod +x $out/bin/miniconda-installer.sh
|
|
||||||
makeWrapper \
|
|
||||||
$out/bin/miniconda-installer.sh \
|
|
||||||
$out/bin/conda-install \
|
|
||||||
--add-flags "-p ${installPath}" \
|
|
||||||
--add-flags "-b"
|
|
||||||
''
|
|
||||||
else if stdenv.isLinux then
|
|
||||||
runCommand "conda-install" {
|
|
||||||
nativeBuildInputs = [ makeWrapper ];
|
|
||||||
buildInputs = [ pkgs.zlib ];
|
|
||||||
}
|
|
||||||
# on line 10, we have 'unset LD_LIBRARY_PATH'
|
|
||||||
# we have to comment it out however in a way that the number of bytes in the
|
|
||||||
# file does not change. So we replace the 'u' in the line with a '#'
|
|
||||||
# The reason is that the binary payload is encoded as number
|
|
||||||
# of bytes from the top of the installer script
|
|
||||||
# and unsetting the library path prevents the zlib library from being discovered
|
|
||||||
''
|
|
||||||
mkdir -p $out/bin
|
|
||||||
sed 's/unset LD_LIBRARY_PATH/#nset LD_LIBRARY_PATH/' ${src} > $out/bin/miniconda-installer.sh
|
|
||||||
chmod +x $out/bin/miniconda-installer.sh
|
|
||||||
makeWrapper \
|
|
||||||
$out/bin/miniconda-installer.sh \
|
|
||||||
$out/bin/conda-install \
|
|
||||||
--add-flags "-p ${installPath}" \
|
|
||||||
--add-flags "-b" \
|
|
||||||
--prefix "LD_LIBRARY_PATH" : "${libPath}"
|
|
||||||
''
|
|
||||||
else {};
|
|
||||||
|
|
||||||
hook = ''
|
|
||||||
export CONDA_SUBDIR=${condaArch}
|
|
||||||
'' + shellHook;
|
|
||||||
|
|
||||||
fhs = buildFHSUserEnv {
|
|
||||||
name = "conda-shell";
|
|
||||||
targetPkgs = pkgs: [ stdenv.cc pkgs.git installer ] ++ packages;
|
|
||||||
profile = hook;
|
|
||||||
runScript = "bash";
|
|
||||||
};
|
|
||||||
|
|
||||||
shell = mkShell {
|
|
||||||
shellHook = if stdenv.isDarwin then hook else "conda-shell; exit";
|
|
||||||
packages = if stdenv.isDarwin then [ pkgs.git installer ] ++ packages else [ fhs ];
|
|
||||||
};
|
|
||||||
in shell;
|
|
||||||
|
|
||||||
packages = with pkgs; [
|
|
||||||
cmake
|
|
||||||
protobuf
|
|
||||||
libiconv
|
|
||||||
rustc
|
|
||||||
cargo
|
|
||||||
rustPlatform.bindgenHook
|
|
||||||
];
|
|
||||||
|
|
||||||
env = {
|
|
||||||
aarch64-darwin = {
|
|
||||||
envFile = "environment-mac.yml";
|
|
||||||
condaPath = (builtins.toString ./.) + "/.conda";
|
|
||||||
ptrSize = "8";
|
|
||||||
};
|
|
||||||
x86_64-linux = {
|
|
||||||
envFile = "environment.yml";
|
|
||||||
condaPath = (builtins.toString ./.) + "/.conda";
|
|
||||||
ptrSize = "8";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
envFile = env.${stdenv.system}.envFile;
|
|
||||||
installPath = env.${stdenv.system}.condaPath;
|
|
||||||
ptrSize = env.${stdenv.system}.ptrSize;
|
|
||||||
shellHook = ''
|
|
||||||
conda-install
|
|
||||||
|
|
||||||
# tmpdir is too small in nix
|
|
||||||
export TMPDIR="${installPath}/tmp"
|
|
||||||
|
|
||||||
# Add conda to PATH
|
|
||||||
export PATH="${installPath}/bin:$PATH"
|
|
||||||
|
|
||||||
# Allows `conda activate` to work properly
|
|
||||||
source ${installPath}/etc/profile.d/conda.sh
|
|
||||||
|
|
||||||
# Paths for gcc if compiling some C sources with pip
|
|
||||||
export NIX_CFLAGS_COMPILE="-I${installPath}/include -I$TMPDIR/include"
|
|
||||||
export NIX_CFLAGS_LINK="-L${installPath}/lib $BINDGEN_EXTRA_CLANG_ARGS"
|
|
||||||
|
|
||||||
export PIP_EXISTS_ACTION=w
|
|
||||||
|
|
||||||
# rust-onig fails (think it writes config.h to wrong location)
|
|
||||||
mkdir -p "$TMPDIR/include"
|
|
||||||
cat <<'EOF' > "$TMPDIR/include/config.h"
|
|
||||||
#define HAVE_PROTOTYPES 1
|
|
||||||
#define STDC_HEADERS 1
|
|
||||||
#define HAVE_STRING_H 1
|
|
||||||
#define HAVE_STDARG_H 1
|
|
||||||
#define HAVE_STDLIB_H 1
|
|
||||||
#define HAVE_LIMITS_H 1
|
|
||||||
#define HAVE_INTTYPES_H 1
|
|
||||||
#define SIZEOF_INT 4
|
|
||||||
#define SIZEOF_SHORT 2
|
|
||||||
#define SIZEOF_LONG ${ptrSize}
|
|
||||||
#define SIZEOF_VOIDP ${ptrSize}
|
|
||||||
#define SIZEOF_LONG_LONG 8
|
|
||||||
EOF
|
|
||||||
|
|
||||||
conda env create -f "${envFile}" || conda env update --prune -f "${envFile}"
|
|
||||||
conda activate invokeai
|
|
||||||
'';
|
|
||||||
|
|
||||||
version = "4.12.0";
|
|
||||||
conda = {
|
|
||||||
aarch64-darwin = {
|
|
||||||
shell = conda-shell {
|
|
||||||
inherit shellHook installPath;
|
|
||||||
url = "https://repo.anaconda.com/miniconda/Miniconda3-py39_${version}-MacOSX-arm64.sh";
|
|
||||||
sha256 = "4bd112168cc33f8a4a60d3ef7e72b52a85972d588cd065be803eb21d73b625ef";
|
|
||||||
packages = [ frameworks.Security ] ++ packages;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
x86_64-linux = {
|
|
||||||
shell = conda-shell {
|
|
||||||
inherit shellHook installPath;
|
|
||||||
url = "https://repo.continuum.io/miniconda/Miniconda3-py39_${version}-Linux-x86_64.sh";
|
|
||||||
sha256 = "78f39f9bae971ec1ae7969f0516017f2413f17796670f7040725dd83fcff5689";
|
|
||||||
packages = with pkgs; [ libGL glib ] ++ packages;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
in conda.${stdenv.system}.shell
|
|
@ -84,6 +84,21 @@ def test_env_override():
|
|||||||
assert conf.max_cache_size == 20
|
assert conf.max_cache_size == 20
|
||||||
|
|
||||||
|
|
||||||
|
def test_root_resists_cwd():
|
||||||
|
previous = os.environ["INVOKEAI_ROOT"]
|
||||||
|
cwd = Path(os.getcwd()).resolve()
|
||||||
|
|
||||||
|
os.environ["INVOKEAI_ROOT"] = "."
|
||||||
|
conf = InvokeAIAppConfig.get_config()
|
||||||
|
conf.parse_args([])
|
||||||
|
assert conf.root_path == cwd
|
||||||
|
|
||||||
|
os.chdir("..")
|
||||||
|
assert conf.root_path == cwd
|
||||||
|
os.environ["INVOKEAI_ROOT"] = previous
|
||||||
|
os.chdir(cwd)
|
||||||
|
|
||||||
|
|
||||||
def test_type_coercion():
|
def test_type_coercion():
|
||||||
conf = InvokeAIAppConfig().get_config()
|
conf = InvokeAIAppConfig().get_config()
|
||||||
conf.parse_args(argv=["--root=/tmp/foobar"])
|
conf.parse_args(argv=["--root=/tmp/foobar"])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user