Merge branch 'main' into feat/execution-stats

This commit is contained in:
psychedelicious 2023-08-03 10:53:25 +10:00 committed by GitHub
commit cf72eba15c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 98 additions and 94 deletions

View File

@ -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 .

View File

@ -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"

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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",

View File

@ -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())

View File

@ -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

View File

@ -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();

View File

@ -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);

View File

@ -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>

View File

@ -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,

View File

@ -18,6 +18,7 @@ export type GalleryState = {
selection: string[];
shouldAutoSwitch: boolean;
autoAddBoardId: string | undefined;
autoAssignBoardOnClick: boolean;
galleryImageMinimumWidth: number;
selectedBoardId: BoardId;
galleryView: GalleryView;