mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge branch 'main' into feat/execution-stats
This commit is contained in:
commit
cf72eba15c
14
.github/workflows/style-checks.yml
vendored
14
.github/workflows/style-checks.yml
vendored
@ -1,13 +1,14 @@
|
||||
name: Black # TODO: add isort and flake8 later
|
||||
name: style checks
|
||||
# just formatting for now
|
||||
# TODO: add isort and flake8 later
|
||||
|
||||
on:
|
||||
pull_request: {}
|
||||
pull_request:
|
||||
push:
|
||||
branches: master
|
||||
tags: "*"
|
||||
branches: main
|
||||
|
||||
jobs:
|
||||
test:
|
||||
black:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@ -19,8 +20,7 @@ jobs:
|
||||
|
||||
- name: Install dependencies with pip
|
||||
run: |
|
||||
pip install --upgrade pip wheel
|
||||
pip install .[test]
|
||||
pip install black
|
||||
|
||||
# - run: isort --check-only .
|
||||
- run: black --check .
|
||||
|
50
.github/workflows/test-invoke-pip-skip.yml
vendored
50
.github/workflows/test-invoke-pip-skip.yml
vendored
@ -1,50 +0,0 @@
|
||||
name: Test invoke.py pip
|
||||
|
||||
# This is a dummy stand-in for the actual tests
|
||||
# we don't need to run python tests on non-Python changes
|
||||
# But PRs require passing tests to be mergeable
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**'
|
||||
- '!pyproject.toml'
|
||||
- '!invokeai/**'
|
||||
- '!tests/**'
|
||||
- 'invokeai/frontend/web/**'
|
||||
merge_group:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
matrix:
|
||||
if: github.event.pull_request.draft == false
|
||||
strategy:
|
||||
matrix:
|
||||
python-version:
|
||||
- '3.10'
|
||||
pytorch:
|
||||
- linux-cuda-11_7
|
||||
- linux-rocm-5_2
|
||||
- linux-cpu
|
||||
- macos-default
|
||||
- windows-cpu
|
||||
include:
|
||||
- pytorch: linux-cuda-11_7
|
||||
os: ubuntu-22.04
|
||||
- pytorch: linux-rocm-5_2
|
||||
os: ubuntu-22.04
|
||||
- pytorch: linux-cpu
|
||||
os: ubuntu-22.04
|
||||
- pytorch: macos-default
|
||||
os: macOS-12
|
||||
- pytorch: windows-cpu
|
||||
os: windows-2022
|
||||
name: ${{ matrix.pytorch }} on ${{ matrix.python-version }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: skip
|
||||
run: echo "no build required"
|
24
.github/workflows/test-invoke-pip.yml
vendored
24
.github/workflows/test-invoke-pip.yml
vendored
@ -3,16 +3,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
paths:
|
||||
- 'pyproject.toml'
|
||||
- 'invokeai/**'
|
||||
- '!invokeai/frontend/web/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'pyproject.toml'
|
||||
- 'invokeai/**'
|
||||
- 'tests/**'
|
||||
- '!invokeai/frontend/web/**'
|
||||
types:
|
||||
- 'ready_for_review'
|
||||
- 'opened'
|
||||
@ -65,10 +56,23 @@ jobs:
|
||||
id: checkout-sources
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Check for changed python files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v37
|
||||
with:
|
||||
files_yaml: |
|
||||
python:
|
||||
- 'pyproject.toml'
|
||||
- 'invokeai/**'
|
||||
- '!invokeai/frontend/web/**'
|
||||
- 'tests/**'
|
||||
|
||||
- name: set test prompt to main branch validation
|
||||
if: steps.changed-files.outputs.python_any_changed == 'true'
|
||||
run: echo "TEST_PROMPTS=tests/validate_pr_prompt.txt" >> ${{ matrix.github-env }}
|
||||
|
||||
- name: setup python
|
||||
if: steps.changed-files.outputs.python_any_changed == 'true'
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
@ -76,6 +80,7 @@ jobs:
|
||||
cache-dependency-path: pyproject.toml
|
||||
|
||||
- name: install invokeai
|
||||
if: steps.changed-files.outputs.python_any_changed == 'true'
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: ${{ matrix.extra-index-url }}
|
||||
run: >
|
||||
@ -83,6 +88,7 @@ jobs:
|
||||
--editable=".[test]"
|
||||
|
||||
- name: run pytest
|
||||
if: steps.changed-files.outputs.python_any_changed == 'true'
|
||||
id: run-pytest
|
||||
run: pytest
|
||||
|
||||
|
@ -289,9 +289,10 @@ class ImageService(ImageServiceABC):
|
||||
def get_metadata(self, image_name: str) -> Optional[ImageMetadata]:
|
||||
try:
|
||||
image_record = self._services.image_records.get(image_name)
|
||||
metadata = self._services.image_records.get_metadata(image_name)
|
||||
|
||||
if not image_record.session_id:
|
||||
return ImageMetadata()
|
||||
return ImageMetadata(metadata=metadata)
|
||||
|
||||
session_raw = self._services.graph_execution_manager.get_raw(image_record.session_id)
|
||||
graph = None
|
||||
@ -303,7 +304,6 @@ class ImageService(ImageServiceABC):
|
||||
self._services.logger.warn(f"Failed to parse session graph: {e}")
|
||||
graph = None
|
||||
|
||||
metadata = self._services.image_records.get_metadata(image_name)
|
||||
return ImageMetadata(graph=graph, metadata=metadata)
|
||||
except ImageRecordNotFoundException:
|
||||
self._services.logger.error("Image record not found")
|
||||
|
@ -78,10 +78,9 @@ class InvokeAIDiffuserComponent:
|
||||
self.cross_attention_control_context = None
|
||||
self.sequential_guidance = config.sequential_guidance
|
||||
|
||||
@classmethod
|
||||
@contextmanager
|
||||
def custom_attention_context(
|
||||
cls,
|
||||
self,
|
||||
unet: UNet2DConditionModel, # note: also may futz with the text encoder depending on requested LoRAs
|
||||
extra_conditioning_info: Optional[ExtraConditioningInfo],
|
||||
step_count: int,
|
||||
@ -91,18 +90,19 @@ class InvokeAIDiffuserComponent:
|
||||
old_attn_processors = unet.attn_processors
|
||||
# Load lora conditions into the model
|
||||
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,
|
||||
step_count=step_count,
|
||||
)
|
||||
setup_cross_attention_control_attention_processors(
|
||||
unet,
|
||||
cross_attention_control_context,
|
||||
self.cross_attention_control_context,
|
||||
)
|
||||
|
||||
try:
|
||||
yield None
|
||||
finally:
|
||||
self.cross_attention_control_context = None
|
||||
if old_attn_processors is not None:
|
||||
unet.set_attn_processor(old_attn_processors)
|
||||
# TODO resuscitate attention map saving
|
||||
|
@ -124,7 +124,8 @@
|
||||
"deleteImageBin": "Deleted images will be sent to your operating system's Bin.",
|
||||
"deleteImagePermanent": "Deleted images cannot be restored.",
|
||||
"images": "Images",
|
||||
"assets": "Assets"
|
||||
"assets": "Assets",
|
||||
"autoAssignBoardOnClick": "Auto-Assign Board on Click"
|
||||
},
|
||||
"hotkeys": {
|
||||
"keyboardShortcuts": "Keyboard Shortcuts",
|
||||
|
@ -11,11 +11,14 @@ import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
|
||||
|
||||
const selector = createSelector(
|
||||
[stateSelector],
|
||||
({ gallery }) => {
|
||||
const { autoAddBoardId } = gallery;
|
||||
({ gallery, system }) => {
|
||||
const { autoAddBoardId, autoAssignBoardOnClick } = gallery;
|
||||
const { isProcessing } = system;
|
||||
|
||||
return {
|
||||
autoAddBoardId,
|
||||
autoAssignBoardOnClick,
|
||||
isProcessing,
|
||||
};
|
||||
},
|
||||
defaultSelectorOptions
|
||||
@ -23,7 +26,8 @@ const selector = createSelector(
|
||||
|
||||
const BoardAutoAddSelect = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { autoAddBoardId } = useAppSelector(selector);
|
||||
const { autoAddBoardId, autoAssignBoardOnClick, isProcessing } =
|
||||
useAppSelector(selector);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const { boards, hasBoards } = useListAllBoardsQuery(undefined, {
|
||||
selectFromResult: ({ data }) => {
|
||||
@ -67,7 +71,7 @@ const BoardAutoAddSelect = () => {
|
||||
data={boards}
|
||||
nothingFound="No matching Boards"
|
||||
itemComponent={IAIMantineSelectItemWithTooltip}
|
||||
disabled={!hasBoards}
|
||||
disabled={!hasBoards || autoAssignBoardOnClick || isProcessing}
|
||||
filter={(value, item: SelectItem) =>
|
||||
item.label?.toLowerCase().includes(value.toLowerCase().trim()) ||
|
||||
item.value.toLowerCase().includes(value.toLowerCase().trim())
|
||||
|
@ -25,14 +25,17 @@ const BoardContextMenu = memo(
|
||||
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(stateSelector, ({ gallery }) => {
|
||||
createSelector(stateSelector, ({ gallery, system }) => {
|
||||
const isAutoAdd = gallery.autoAddBoardId === board_id;
|
||||
return { isAutoAdd };
|
||||
const isProcessing = system.isProcessing;
|
||||
const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;
|
||||
return { isAutoAdd, isProcessing, autoAssignBoardOnClick };
|
||||
}),
|
||||
[board_id]
|
||||
);
|
||||
|
||||
const { isAutoAdd } = useAppSelector(selector);
|
||||
const { isAutoAdd, isProcessing, autoAssignBoardOnClick } =
|
||||
useAppSelector(selector);
|
||||
const boardName = useBoardName(board_id);
|
||||
|
||||
const handleSetAutoAdd = useCallback(() => {
|
||||
@ -59,7 +62,7 @@ const BoardContextMenu = memo(
|
||||
<MenuGroup title={boardName}>
|
||||
<MenuItem
|
||||
icon={<FaPlus />}
|
||||
isDisabled={isAutoAdd}
|
||||
isDisabled={isAutoAdd || isProcessing || autoAssignBoardOnClick}
|
||||
onClick={handleSetAutoAdd}
|
||||
>
|
||||
Auto-add to this Board
|
||||
|
@ -16,7 +16,10 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import IAIDroppable from 'common/components/IAIDroppable';
|
||||
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 { FaUser } from 'react-icons/fa';
|
||||
import { useUpdateBoardMutation } from 'services/api/endpoints/boards';
|
||||
@ -38,18 +41,25 @@ const GalleryBoard = memo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ gallery }) => {
|
||||
({ gallery, system }) => {
|
||||
const isSelectedForAutoAdd =
|
||||
board.board_id === gallery.autoAddBoardId;
|
||||
const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;
|
||||
const isProcessing = system.isProcessing;
|
||||
|
||||
return { isSelectedForAutoAdd };
|
||||
return {
|
||||
isSelectedForAutoAdd,
|
||||
autoAssignBoardOnClick,
|
||||
isProcessing,
|
||||
};
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
[board.board_id]
|
||||
);
|
||||
|
||||
const { isSelectedForAutoAdd } = useAppSelector(selector);
|
||||
const { isSelectedForAutoAdd, autoAssignBoardOnClick, isProcessing } =
|
||||
useAppSelector(selector);
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const handleMouseOver = useCallback(() => {
|
||||
setIsHovered(true);
|
||||
@ -66,7 +76,10 @@ const GalleryBoard = memo(
|
||||
|
||||
const handleSelectBoard = useCallback(() => {
|
||||
dispatch(boardIdSelected(board_id));
|
||||
}, [board_id, dispatch]);
|
||||
if (autoAssignBoardOnClick && !isProcessing) {
|
||||
dispatch(autoAddBoardIdChanged(board_id));
|
||||
}
|
||||
}, [board_id, autoAssignBoardOnClick, isProcessing, dispatch]);
|
||||
|
||||
const [updateBoard, { isLoading: isUpdateBoardLoading }] =
|
||||
useUpdateBoardMutation();
|
||||
|
@ -7,7 +7,10 @@ import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import InvokeAILogoImage from 'assets/images/logo.png';
|
||||
import IAIDroppable from 'common/components/IAIDroppable';
|
||||
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 { useBoardName } from 'services/api/hooks/useBoardName';
|
||||
import AutoAddIcon from '../AutoAddIcon';
|
||||
@ -18,20 +21,25 @@ interface Props {
|
||||
|
||||
const selector = createSelector(
|
||||
stateSelector,
|
||||
({ gallery }) => {
|
||||
const { autoAddBoardId } = gallery;
|
||||
return { autoAddBoardId };
|
||||
({ gallery, system }) => {
|
||||
const { autoAddBoardId, autoAssignBoardOnClick } = gallery;
|
||||
const { isProcessing } = system;
|
||||
return { autoAddBoardId, autoAssignBoardOnClick, isProcessing };
|
||||
},
|
||||
defaultSelectorOptions
|
||||
);
|
||||
|
||||
const NoBoardBoard = memo(({ isSelected }: Props) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { autoAddBoardId } = useAppSelector(selector);
|
||||
const { autoAddBoardId, autoAssignBoardOnClick, isProcessing } =
|
||||
useAppSelector(selector);
|
||||
const boardName = useBoardName(undefined);
|
||||
const handleSelectBoard = useCallback(() => {
|
||||
dispatch(boardIdSelected(undefined));
|
||||
}, [dispatch]);
|
||||
if (autoAssignBoardOnClick && !isProcessing) {
|
||||
dispatch(autoAddBoardIdChanged(undefined));
|
||||
}
|
||||
}, [dispatch, autoAssignBoardOnClick, isProcessing]);
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const handleMouseOver = useCallback(() => {
|
||||
setIsHovered(true);
|
||||
|
@ -8,6 +8,7 @@ import IAIPopover from 'common/components/IAIPopover';
|
||||
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import {
|
||||
autoAssignBoardOnClickChanged,
|
||||
setGalleryImageMinimumWidth,
|
||||
shouldAutoSwitchChanged,
|
||||
} from 'features/gallery/store/gallerySlice';
|
||||
@ -19,11 +20,16 @@ import BoardAutoAddSelect from './Boards/BoardAutoAddSelect';
|
||||
const selector = createSelector(
|
||||
[stateSelector],
|
||||
(state) => {
|
||||
const { galleryImageMinimumWidth, shouldAutoSwitch } = state.gallery;
|
||||
const {
|
||||
galleryImageMinimumWidth,
|
||||
shouldAutoSwitch,
|
||||
autoAssignBoardOnClick,
|
||||
} = state.gallery;
|
||||
|
||||
return {
|
||||
galleryImageMinimumWidth,
|
||||
shouldAutoSwitch,
|
||||
autoAssignBoardOnClick,
|
||||
};
|
||||
},
|
||||
defaultSelectorOptions
|
||||
@ -33,7 +39,7 @@ const GallerySettingsPopover = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { galleryImageMinimumWidth, shouldAutoSwitch } =
|
||||
const { galleryImageMinimumWidth, shouldAutoSwitch, autoAssignBoardOnClick } =
|
||||
useAppSelector(selector);
|
||||
|
||||
const handleChangeGalleryImageMinimumWidth = (v: number) => {
|
||||
@ -69,6 +75,13 @@ const GallerySettingsPopover = () => {
|
||||
dispatch(shouldAutoSwitchChanged(e.target.checked))
|
||||
}
|
||||
/>
|
||||
<IAISimpleCheckbox
|
||||
label={t('gallery.autoAssignBoardOnClick')}
|
||||
isChecked={autoAssignBoardOnClick}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
dispatch(autoAssignBoardOnClickChanged(e.target.checked))
|
||||
}
|
||||
/>
|
||||
<BoardAutoAddSelect />
|
||||
</Flex>
|
||||
</IAIPopover>
|
||||
|
@ -8,6 +8,7 @@ export const initialGalleryState: GalleryState = {
|
||||
selection: [],
|
||||
shouldAutoSwitch: true,
|
||||
autoAddBoardId: undefined,
|
||||
autoAssignBoardOnClick: true,
|
||||
galleryImageMinimumWidth: 96,
|
||||
selectedBoardId: undefined,
|
||||
galleryView: 'images',
|
||||
@ -66,6 +67,9 @@ export const gallerySlice = createSlice({
|
||||
setGalleryImageMinimumWidth: (state, action: PayloadAction<number>) => {
|
||||
state.galleryImageMinimumWidth = action.payload;
|
||||
},
|
||||
autoAssignBoardOnClickChanged: (state, action: PayloadAction<boolean>) => {
|
||||
state.autoAssignBoardOnClick = action.payload;
|
||||
},
|
||||
boardIdSelected: (state, action: PayloadAction<BoardId>) => {
|
||||
state.selectedBoardId = action.payload;
|
||||
state.galleryView = 'images';
|
||||
@ -140,6 +144,7 @@ export const {
|
||||
imageSelectionToggled,
|
||||
imageSelected,
|
||||
shouldAutoSwitchChanged,
|
||||
autoAssignBoardOnClickChanged,
|
||||
setGalleryImageMinimumWidth,
|
||||
boardIdSelected,
|
||||
isBatchEnabledChanged,
|
||||
|
@ -18,6 +18,7 @@ export type GalleryState = {
|
||||
selection: string[];
|
||||
shouldAutoSwitch: boolean;
|
||||
autoAddBoardId: string | undefined;
|
||||
autoAssignBoardOnClick: boolean;
|
||||
galleryImageMinimumWidth: number;
|
||||
selectedBoardId: BoardId;
|
||||
galleryView: GalleryView;
|
||||
|
Loading…
Reference in New Issue
Block a user