Merge branch 'main' into 2.3-documentation-fixes

This commit is contained in:
Lincoln Stein 2023-02-07 17:08:10 -05:00
commit 13d12a0ceb
290 changed files with 10991 additions and 3790 deletions

View File

@ -3,6 +3,7 @@ on:
push:
branches:
- 'main'
- 'update/ci/*'
tags:
- 'v*.*.*'
@ -47,11 +48,10 @@ jobs:
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha,enable=true,prefix=sha-,suffix=${{ matrix.flavor}},format=short
type=raw,value={{branch}}-${{ matrix.flavor }}
type=sha,enable=true,prefix=sha-,format=short
flavor: |
latest=${{ matrix.flavor == 'cuda' && github.ref == 'refs/heads/main' }}
suffix=-${{ matrix.flavor }},onlatest=false
- name: Set up QEMU
uses: docker/setup-qemu-action@v2

View File

@ -8,10 +8,11 @@ on:
- 'ready_for_review'
- 'opened'
- 'synchronize'
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
matrix:
@ -62,28 +63,13 @@ jobs:
# github-env: $env:GITHUB_ENV
name: ${{ matrix.pytorch }} on ${{ matrix.python-version }}
runs-on: ${{ matrix.os }}
env:
PIP_USE_PEP517: '1'
steps:
- name: Checkout sources
id: checkout-sources
uses: actions/checkout@v3
- name: setup python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Set Cache-Directory Windows
if: runner.os == 'Windows'
id: set-cache-dir-windows
run: |
echo "CACHE_DIR=$HOME\invokeai\models" >> ${{ matrix.github-env }}
echo "PIP_NO_CACHE_DIR=1" >> ${{ matrix.github-env }}
- name: Set Cache-Directory others
if: runner.os != 'Windows'
id: set-cache-dir-others
run: echo "CACHE_DIR=$HOME/invokeai/models" >> ${{ matrix.github-env }}
- name: set test prompt to main branch validation
if: ${{ github.ref == 'refs/heads/main' }}
run: echo "TEST_PROMPTS=tests/preflight_prompts.txt" >> ${{ matrix.github-env }}
@ -92,26 +78,29 @@ jobs:
if: ${{ github.ref != 'refs/heads/main' }}
run: echo "TEST_PROMPTS=tests/validate_pr_prompt.txt" >> ${{ matrix.github-env }}
- name: setup python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: pyproject.toml
- name: install invokeai
env:
PIP_EXTRA_INDEX_URL: ${{ matrix.extra-index-url }}
run: >
pip3 install
--use-pep517
--editable=".[test]"
- name: run pytest
id: run-pytest
run: pytest
- name: Use Cached models
id: cache-sd-model
uses: actions/cache@v3
env:
cache-name: huggingface-models
with:
path: ${{ env.CACHE_DIR }}
key: ${{ env.cache-name }}
enableCrossOsArchive: true
- name: set INVOKEAI_OUTDIR
run: >
python -c
"import os;from ldm.invoke.globals import Globals;OUTDIR=os.path.join(Globals.root,str('outputs'));print(f'INVOKEAI_OUTDIR={OUTDIR}')"
>> ${{ matrix.github-env }}
- name: run invokeai-configure
id: run-preload-models
@ -124,9 +113,8 @@ jobs:
--full-precision
# can't use fp16 weights without a GPU
- name: Run the tests
if: runner.os != 'Windows'
id: run-tests
- name: run invokeai
id: run-invokeai
env:
# Set offline mode to make sure configure preloaded successfully.
HF_HUB_OFFLINE: 1
@ -137,10 +125,11 @@ jobs:
--no-patchmatch
--no-nsfw_checker
--from_file ${{ env.TEST_PROMPTS }}
--outdir ${{ env.INVOKEAI_OUTDIR }}/${{ matrix.python-version }}/${{ matrix.pytorch }}
- name: Archive results
id: archive-results
uses: actions/upload-artifact@v3
with:
name: results_${{ matrix.pytorch }}_${{ matrix.python-version }}
path: ${{ env.INVOKEAI_ROOT }}/outputs
name: results
path: ${{ env.INVOKEAI_OUTDIR }}

View File

@ -1,7 +1,4 @@
# syntax=docker/dockerfile:1
# Maintained by Matthias Wild <mauwii@outlook.de>
ARG PYTHON_VERSION=3.9
##################
## base image ##
@ -85,3 +82,5 @@ ENV INVOKE_MODEL_RECONFIGURE="--yes --default_only"
ENTRYPOINT [ "invokeai" ]
CMD [ "--web", "--host=0.0.0.0" ]
VOLUME [ "/data" ]
LABEL org.opencontainers.image.authors="mauwii@outlook.de"

View File

@ -54,8 +54,7 @@ Please enter 1, 2, 3, or 4: [1] 3
```
From the command line, with the InvokeAI virtual environment active,
you can launch the front end with the command `textual_inversion
--gui`.
you can launch the front end with the command `invokeai-ti --gui`.
This will launch a text-based front end that will look like this:
@ -227,12 +226,12 @@ It accepts a large number of arguments, which can be summarized by
passing the `--help` argument:
```sh
textual_inversion --help
invokeai-ti --help
```
Typical usage is shown here:
```sh
textual_inversion \
invokeai-ti \
--model=stable-diffusion-1.5 \
--resolution=512 \
--learnable_property=style \
@ -267,4 +266,4 @@ resources:
---
copyright (c) 2023, Lincoln Stein and the InvokeAI Development Team
copyright (c) 2023, Lincoln Stein and the InvokeAI Development Team

View File

@ -249,6 +249,7 @@ class InvokeAiInstance:
"--require-virtualenv",
"torch",
"torchvision",
"--force-reinstall",
"--find-links" if find_links is not None else None,
find_links,
"--extra-index-url" if extra_index_url is not None else None,
@ -325,6 +326,7 @@ class InvokeAiInstance:
Configure the InvokeAI runtime directory
"""
# set sys.argv to a consistent state
new_argv = [sys.argv[0]]
for i in range(1,len(sys.argv)):
el = sys.argv[i]
@ -344,9 +346,6 @@ class InvokeAiInstance:
# NOTE: currently the config script does its own arg parsing! this means the command-line switches
# from the installer will also automatically propagate down to the config script.
# this may change in the future with config refactoring!
# set sys.argv to a consistent state
invokeai_configure.main()
def install_user_scripts(self):

View File

@ -1208,12 +1208,18 @@ class InvokeAIWebServer:
)
except KeyboardInterrupt:
# Clear the CUDA cache on an exception
self.empty_cuda_cache()
self.socketio.emit("processingCanceled")
raise
except CanceledException:
# Clear the CUDA cache on an exception
self.empty_cuda_cache()
self.socketio.emit("processingCanceled")
pass
except Exception as e:
# Clear the CUDA cache on an exception
self.empty_cuda_cache()
print(e)
self.socketio.emit("error", {"message": (str(e))})
print("\n")
@ -1221,6 +1227,12 @@ class InvokeAIWebServer:
traceback.print_exc()
print("\n")
def empty_cuda_cache(self):
if self.generate.device.type == "cuda":
import torch.cuda
torch.cuda.empty_cache()
def parameters_to_generated_image_metadata(self, parameters):
try:
# top-level metadata minus `image` or `images`

View File

@ -0,0 +1,13 @@
{
"plugins": [
[
"transform-imports",
{
"lodash": {
"transform": "lodash/${member}",
"preventFullImport": true
}
}
]
]
}

View File

@ -0,0 +1,5 @@
dist/
.husky/
node_modules/
patches/
public/

View File

@ -1,13 +0,0 @@
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'eslint-plugin-react-hooks'],
root: true,
rules: {
'@typescript-eslint/no-unused-vars': ['warn', { varsIgnorePattern: '_+' }],
},
};

View File

@ -0,0 +1,40 @@
module.exports = {
env: {
browser: true,
es6: true,
node: true,
},
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:prettier/recommended',
'plugin:react/jsx-runtime',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 2018,
sourceType: 'module',
},
plugins: ['react', '@typescript-eslint', 'eslint-plugin-react-hooks'],
root: true,
rules: {
'react-hooks/exhaustive-deps': 'error',
'no-var': 'error',
'brace-style': 'error',
'prefer-template': 'error',
radix: 'error',
'space-before-blocks': 'error',
'import/prefer-default-export': 'off',
'@typescript-eslint/no-unused-vars': ['warn', { varsIgnorePattern: '_+' }],
},
settings: {
react: {
version: 'detect',
},
},
};

View File

@ -23,3 +23,6 @@ dist-ssr
*.njsproj
*.sln
*.sw?
# build stats
stats.html

View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
cd invokeai/frontend/ && npx run lint

View File

@ -0,0 +1,5 @@
dist/
.husky/
node_modules/
patches/
public/

View File

@ -0,0 +1,6 @@
module.exports = {
trailingComma: 'es5',
tabWidth: 2,
semi: true,
singleQuote: true,
};

View File

@ -17,4 +17,4 @@ From `invokeai/frontend/` run `yarn install` to get everything set up.
To build for dev: `yarn build-dev`
To build for production: `yarn build`
To build for production: `yarn build`

View File

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 116 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,23 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script type="module" crossorigin src="./assets/polyfills.1ff60148.js"></script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>InvokeAI - A Stable Diffusion Toolkit</title>
<link rel="shortcut icon" type="icon" href="./assets/favicon.0d253ced.ico" />
<script type="module" crossorigin src="./assets/index.dd4ad8a1.js"></script>
<link rel="stylesheet" href="./assets/index.8badc8b4.css">
<script type="module">try{import.meta.url;import("_").catch(()=>1);}catch(e){}window.__vite_is_modern_browser=true;</script>
<script type="module">!function(){if(window.__vite_is_modern_browser)return;console.warn("vite: loading legacy build because dynamic import or import.meta.url is unsupported, syntax error above should be ignored");var e=document.getElementById("vite-legacy-polyfill"),n=document.createElement("script");n.src=e.src,n.onload=function(){System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))},document.body.appendChild(n)}();</script>
<link rel="shortcut icon" type="icon" href="./assets/favicon-0d253ced.ico" />
<script type="module" crossorigin src="./assets/index-34c8aef8.js"></script>
<link rel="stylesheet" href="./assets/index-b0bf79f4.css">
</head>
<body>
<div id="root"></div>
<script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
<script nomodule crossorigin id="vite-legacy-polyfill" src="./assets/polyfills-legacy-dde3a68a.js"></script>
<script nomodule crossorigin id="vite-legacy-entry" data-src="./assets/index-legacy-8219c08f.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
</body>
</html>

View File

@ -24,6 +24,7 @@
"otherOptions": "Other Options",
"seamlessTiling": "Seamless Tiling",
"hiresOptim": "High Res Optimization",
"hiresStrength": "High Res Strength",
"imageFit": "Fit Initial Image To Output Size",
"codeformerFidelity": "Fidelity",
"seamSize": "Seam Size",

View File

@ -24,6 +24,7 @@
"otherOptions": "Other Options",
"seamlessTiling": "Seamless Tiling",
"hiresOptim": "High Res Optimization",
"hiresStrength": "High Res Strength",
"imageFit": "Fit Initial Image To Output Size",
"codeformerFidelity": "Fidelity",
"seamSize": "Seam Size",
@ -43,6 +44,7 @@
"invoke": "Invoke",
"cancel": "Cancel",
"promptPlaceholder": "Type prompt here. [negative tokens], (upweight)++, (downweight)--, swap and blend are available (see docs)",
"negativePrompts": "Negative Prompts",
"sendTo": "Send to",
"sendToImg2Img": "Send to Image to Image",
"sendToUnifiedCanvas": "Send To Unified Canvas",

View File

@ -1,23 +0,0 @@
{
"eslintConfig": {
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended"
],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "eslint-plugin-react-hooks"],
"root": true,
"settings": {
"import/resolver": {
"node": {
"paths": ["src"],
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
}
},
"rules": {
"react/jsx-filename-extension": [1, { "extensions": [".tsx", ".ts"] }]
}
}
}

View File

@ -2,15 +2,15 @@
"name": "invoke-ai-ui",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"prepare": "cd ../../ && husky install invokeai/frontend/.husky",
"dev": "vite dev",
"build": "tsc && vite build",
"build-dev": "tsc && vite build -m development",
"preview": "vite preview",
"madge": "madge --circular src/main.tsx",
"lint": "eslint src/",
"prettier": "prettier *.{json,cjs,ts,html} src/**/*.{ts,tsx}",
"lint": "eslint --fix .",
"lint-staged": "lint-staged",
"prettier": "prettier *.{json,js,ts,html} src/**/*.{ts,tsx,scss} --write .",
"fmt": "npm run prettier -- --write",
"postinstall": "patch-package"
},
@ -25,6 +25,7 @@
"@radix-ui/react-tooltip": "^1.0.2",
"@reduxjs/toolkit": "^1.8.5",
"@types/uuid": "^8.3.4",
"@vitejs/plugin-react-swc": "^3.1.0",
"add": "^2.0.6",
"dateformat": "^5.0.3",
"formik": "^2.2.9",
@ -62,22 +63,26 @@
"@types/react-transition-group": "^4.4.5",
"@typescript-eslint/eslint-plugin": "^5.36.2",
"@typescript-eslint/parser": "^5.36.2",
"@vitejs/plugin-legacy": "^3.0.1",
"@vitejs/plugin-react": "^2.0.1",
"babel-plugin-transform-imports": "^2.0.0",
"eslint": "^8.23.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"husky": "^8.0.3",
"lint-staged": "^13.1.0",
"madge": "^5.0.1",
"patch-package": "^6.5.0",
"postinstall-postinstall": "^2.1.0",
"prettier": "^2.8.1",
"prettier": "^2.8.3",
"rollup-plugin-visualizer": "^5.9.0",
"sass": "^1.55.0",
"terser": "^5.16.1",
"tsc-watch": "^5.0.3",
"typescript": "^4.6.4",
"vite": "^3.0.7",
"typescript": "^5.0.0-beta",
"vite": "^4.1.1",
"vite-plugin-eslint": "^1.8.1",
"vite-tsconfig-paths": "^3.5.2"
"vite-tsconfig-paths": "^4.0.5"
},
"madge": {
"detectiveOptions": {
@ -88,5 +93,11 @@
"skipTypeImports": true
}
}
},
"lint-staged": {
"**/*.{js,jsx,ts,tsx,cjs}": [
"npx prettier --write",
"npx eslint --fix"
]
}
}

View File

@ -24,6 +24,7 @@
"otherOptions": "Other Options",
"seamlessTiling": "Seamless Tiling",
"hiresOptim": "High Res Optimization",
"hiresStrength": "High Res Strength",
"imageFit": "Fit Initial Image To Output Size",
"codeformerFidelity": "Fidelity",
"seamSize": "Seam Size",

View File

@ -24,6 +24,7 @@
"otherOptions": "Other Options",
"seamlessTiling": "Seamless Tiling",
"hiresOptim": "High Res Optimization",
"hiresStrength": "High Res Strength",
"imageFit": "Fit Initial Image To Output Size",
"codeformerFidelity": "Fidelity",
"seamSize": "Seam Size",
@ -43,6 +44,7 @@
"invoke": "Invoke",
"cancel": "Cancel",
"promptPlaceholder": "Type prompt here. [negative tokens], (upweight)++, (downweight)--, swap and blend are available (see docs)",
"negativePrompts": "Negative Prompts",
"sendTo": "Send to",
"sendToImg2Img": "Send to Image to Image",
"sendToUnifiedCanvas": "Send To Unified Canvas",

View File

@ -1,14 +1,14 @@
import ImageUploader from 'common/components/ImageUploader';
import Console from 'features/system/components/Console';
import ProgressBar from 'features/system/components/ProgressBar';
import SiteHeader from 'features/system/components/SiteHeader';
import Console from 'features/system/components/Console';
import InvokeTabs from 'features/ui/components/InvokeTabs';
import { keepGUIAlive } from './utils';
import InvokeTabs from 'features/tabs/components/InvokeTabs';
import ImageUploader from 'common/components/ImageUploader';
import useToastWatcher from 'features/system/hooks/useToastWatcher';
import FloatingOptionsPanelButtons from 'features/tabs/components/FloatingOptionsPanelButtons';
import FloatingGalleryButton from 'features/tabs/components/FloatingGalleryButton';
import FloatingGalleryButton from 'features/ui/components/FloatingGalleryButton';
import FloatingParametersPanelButtons from 'features/ui/components/FloatingParametersPanelButtons';
keepGUIAlive();
@ -27,7 +27,7 @@ const App = () => {
<Console />
</div>
</ImageUploader>
<FloatingOptionsPanelButtons />
<FloatingParametersPanelButtons />
<FloatingGalleryButton />
</div>
);

View File

@ -16,6 +16,20 @@ export const SAMPLERS: Array<string> = [
'k_heun',
];
// Valid Diffusers Samplers
export const DIFFUSERS_SAMPLERS: Array<string> = [
'ddim',
'plms',
'k_lms',
'dpmpp_2',
'k_dpm_2',
'k_dpm_2_a',
'k_dpmpp_2',
'k_euler',
'k_euler_a',
'k_heun',
];
// Valid image widths
export const WIDTHS: Array<number> = [
64, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960,

View File

@ -12,7 +12,7 @@
* 'gfpgan'.
*/
import { InvokeTabName } from 'features/tabs/tabMap';
import { InvokeTabName } from 'features/ui/store/tabMap';
import { IRect } from 'konva/lib/types';
/**

View File

@ -1,32 +1,26 @@
import { createSelector } from '@reduxjs/toolkit';
import _ from 'lodash';
import { RootState } from 'app/store';
import { activeTabNameSelector } from 'features/options/store/optionsSelectors';
import { OptionsState } from 'features/options/store/optionsSlice';
import { SystemState } from 'features/system/store/systemSlice';
import { validateSeedWeights } from 'common/util/seedWeightPairs';
import { initialCanvasImageSelector } from 'features/canvas/store/canvasSelectors';
import { generationSelector } from 'features/parameters/store/generationSelectors';
import { systemSelector } from 'features/system/store/systemSelectors';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { isEqual } from 'lodash';
export const readinessSelector = createSelector(
[
(state: RootState) => state.options,
(state: RootState) => state.system,
generationSelector,
systemSelector,
initialCanvasImageSelector,
activeTabNameSelector,
],
(
options: OptionsState,
system: SystemState,
initialCanvasImage,
activeTabName
) => {
(generation, system, initialCanvasImage, activeTabName) => {
const {
prompt,
shouldGenerateVariations,
seedWeights,
initialImage,
seed,
} = options;
} = generation;
const { isProcessing, isConnected } = system;
@ -71,8 +65,8 @@ export const readinessSelector = createSelector(
},
{
memoizeOptions: {
equalityCheck: _.isEqual,
resultEqualityCheck: _.isEqual,
equalityCheck: isEqual,
resultEqualityCheck: isEqual,
},
}
);

View File

@ -1,7 +1,7 @@
import { createAction } from '@reduxjs/toolkit';
import { GalleryCategory } from 'features/gallery/store/gallerySlice';
import { InvokeTabName } from 'features/tabs/tabMap';
import * as InvokeAI from 'app/invokeai';
import { GalleryCategory } from 'features/gallery/store/gallerySlice';
import { InvokeTabName } from 'features/ui/store/tabMap';
/**
* We can't use redux-toolkit's createSlice() to make these actions,

View File

@ -1,25 +1,24 @@
import { AnyAction, Dispatch, MiddlewareAPI } from '@reduxjs/toolkit';
import dateFormat from 'dateformat';
import { Socket } from 'socket.io-client';
import * as InvokeAI from 'app/invokeai';
import type { RootState } from 'app/store';
import {
frontendToBackendParameters,
FrontendToBackendParametersConfig,
} from 'common/util/parameterTranslation';
import dateFormat from 'dateformat';
import {
GalleryCategory,
GalleryState,
removeImage,
} from 'features/gallery/store/gallerySlice';
import { OptionsState } from 'features/options/store/optionsSlice';
import {
addLogEntry,
generationRequested,
modelChangeRequested,
setIsProcessing,
} from 'features/system/store/systemSlice';
import { InvokeTabName } from 'features/tabs/tabMap';
import * as InvokeAI from 'app/invokeai';
import type { RootState } from 'app/store';
import { InvokeTabName } from 'features/ui/store/tabMap';
import { Socket } from 'socket.io-client';
/**
* Returns an object containing all functions which use `socketio.emit()`.
@ -39,7 +38,8 @@ const makeSocketIOEmitters = (
const state: RootState = getState();
const {
options: optionsState,
generation: generationState,
postprocessing: postprocessingState,
system: systemState,
canvas: canvasState,
} = state;
@ -47,7 +47,8 @@ const makeSocketIOEmitters = (
const frontendToBackendParametersConfig: FrontendToBackendParametersConfig =
{
generationMode,
optionsState,
generationState,
postprocessingState,
canvasState,
systemState,
};
@ -90,8 +91,11 @@ const makeSocketIOEmitters = (
},
emitRunESRGAN: (imageToProcess: InvokeAI.Image) => {
dispatch(setIsProcessing(true));
const options: OptionsState = getState().options;
const { upscalingLevel, upscalingStrength } = options;
const {
postprocessing: { upscalingLevel, upscalingStrength },
} = getState();
const esrganParameters = {
upscale: [upscalingLevel, upscalingStrength],
};
@ -111,8 +115,10 @@ const makeSocketIOEmitters = (
},
emitRunFacetool: (imageToProcess: InvokeAI.Image) => {
dispatch(setIsProcessing(true));
const options: OptionsState = getState().options;
const { facetoolType, facetoolStrength, codeformerFidelity } = options;
const {
postprocessing: { facetoolType, facetoolStrength, codeformerFidelity },
} = getState();
const facetoolParameters: Record<string, unknown> = {
facetool_strength: facetoolStrength,

View File

@ -1,24 +1,24 @@
import { AnyAction, MiddlewareAPI, Dispatch } from '@reduxjs/toolkit';
import { v4 as uuidv4 } from 'uuid';
import { AnyAction, Dispatch, MiddlewareAPI } from '@reduxjs/toolkit';
import dateFormat from 'dateformat';
import i18n from 'i18n';
import { v4 as uuidv4 } from 'uuid';
import * as InvokeAI from 'app/invokeai';
import {
addLogEntry,
addToast,
errorOccurred,
processingCanceled,
setCurrentStatus,
setFoundModels,
setIsCancelable,
setIsConnected,
setIsProcessing,
setSystemStatus,
setCurrentStatus,
setSystemConfig,
processingCanceled,
errorOccurred,
setModelList,
setIsCancelable,
addToast,
setFoundModels,
setSearchFolder,
setSystemConfig,
setSystemStatus,
} from 'features/system/store/systemSlice';
import {
@ -30,20 +30,20 @@ import {
setIntermediateImage,
} from 'features/gallery/store/gallerySlice';
import type { RootState } from 'app/store';
import { addImageToStagingArea } from 'features/canvas/store/canvasSlice';
import {
clearInitialImage,
setInfillMethod,
setInitialImage,
setMaskPath,
} from 'features/options/store/optionsSlice';
} from 'features/parameters/store/generationSlice';
import { tabMap } from 'features/ui/store/tabMap';
import {
requestImages,
requestNewImages,
requestSystemConfig,
} from './actions';
import { addImageToStagingArea } from 'features/canvas/store/canvasSlice';
import { tabMap } from 'features/tabs/tabMap';
import type { RootState } from 'app/store';
/**
* Returns an object containing listener callbacks for socketio events.
@ -104,8 +104,9 @@ const makeSocketIOListeners = (
*/
onGenerationResult: (data: InvokeAI.ImageResultResponse) => {
try {
const state: RootState = getState();
const { shouldLoopback, activeTab } = state.options;
const state = getState();
const { activeTab } = state.ui;
const { shouldLoopback } = state.postprocessing;
const { boundingBox: _, generationMode, ...rest } = data;
const newImage = {
@ -327,7 +328,9 @@ const makeSocketIOListeners = (
dispatch(removeImage(data));
// remove references to image in options
const { initialImage, maskPath } = getState().options;
const {
generation: { initialImage, maskPath },
} = getState();
if (
initialImage === url ||

View File

@ -1,8 +1,8 @@
import { Middleware } from '@reduxjs/toolkit';
import { io } from 'socket.io-client';
import makeSocketIOListeners from './listeners';
import makeSocketIOEmitters from './emitters';
import makeSocketIOListeners from './listeners';
import * as InvokeAI from 'app/invokeai';
@ -26,7 +26,7 @@ export const socketioMiddleware = () => {
const socketio = io(origin, {
timeout: 60000,
path: window.location.pathname + 'socket.io',
path: `${window.location.pathname}socket.io`,
});
let areListenersSet = false;

View File

@ -5,10 +5,13 @@ import storage from 'redux-persist/lib/storage'; // defaults to localStorage for
import { getPersistConfig } from 'redux-deep-persist';
import optionsReducer from 'features/options/store/optionsSlice';
import galleryReducer from 'features/gallery/store/gallerySlice';
import systemReducer from 'features/system/store/systemSlice';
import canvasReducer from 'features/canvas/store/canvasSlice';
import galleryReducer from 'features/gallery/store/gallerySlice';
import lightboxReducer from 'features/lightbox/store/lightboxSlice';
import generationReducer from 'features/parameters/store/generationSlice';
import postprocessingReducer from 'features/parameters/store/postprocessingSlice';
import systemReducer from 'features/system/store/systemSlice';
import uiReducer from 'features/ui/store/uiSlice';
import { socketioMiddleware } from './socketio/middleware';
@ -58,10 +61,13 @@ const galleryBlacklist = [
].map((blacklistItem) => `gallery.${blacklistItem}`);
const rootReducer = combineReducers({
options: optionsReducer,
generation: generationReducer,
postprocessing: postprocessingReducer,
gallery: galleryReducer,
system: systemReducer,
canvas: canvasReducer,
ui: uiReducer,
lightbox: lightboxReducer,
});
const rootPersistConfig = getPersistConfig({
@ -89,8 +95,8 @@ export const store = configureStore({
'canvas/setStageCoordinates',
'canvas/setStageScale',
'canvas/setIsDrawing',
// 'canvas/setBoundingBoxCoordinates',
// 'canvas/setBoundingBoxDimensions',
'canvas/setBoundingBoxCoordinates',
'canvas/setBoundingBoxDimensions',
'canvas/setIsDrawing',
'canvas/addPointToCurrentLine',
],

View File

@ -1,7 +1,7 @@
import { Box, forwardRef, Icon } from '@chakra-ui/react';
import { Feature } from 'app/features';
import { IconType } from 'react-icons';
import { MdHelp } from 'react-icons/md';
import { Feature } from 'app/features';
import GuidePopover from './GuidePopover';
type GuideIconProps = {

View File

@ -1,29 +1,29 @@
import {
Box,
Popover,
PopoverArrow,
PopoverContent,
PopoverTrigger,
Box,
} from '@chakra-ui/react';
import { SystemState } from 'features/system/store/systemSlice';
import { useAppSelector } from 'app/storeHooks';
import { RootState } from 'app/store';
import { createSelector } from '@reduxjs/toolkit';
import { ReactElement } from 'react';
import { Feature, useFeatureHelpInfo } from 'app/features';
import { useAppSelector } from 'app/storeHooks';
import { systemSelector } from 'features/system/store/systemSelectors';
import { SystemState } from 'features/system/store/systemSlice';
import { ReactElement } from 'react';
type GuideProps = {
children: ReactElement;
feature: Feature;
};
const systemSelector = createSelector(
(state: RootState) => state.system,
const guidePopoverSelector = createSelector(
systemSelector,
(system: SystemState) => system.shouldDisplayGuides
);
const GuidePopover = ({ children, feature }: GuideProps) => {
const shouldDisplayGuides = useAppSelector(systemSelector);
const shouldDisplayGuides = useAppSelector(guidePopoverSelector);
const { text } = useFeatureHelpInfo(feature);
if (!shouldDisplayGuides) return null;

View File

@ -1,9 +1,9 @@
import {
IconButtonProps,
forwardRef,
IconButton,
IconButtonProps,
Tooltip,
TooltipProps,
forwardRef,
} from '@chakra-ui/react';
export type IAIIconButtonProps = IconButtonProps & {

View File

@ -1,19 +1,20 @@
import {
FormControl,
FormControlProps,
FormLabel,
FormLabelProps,
NumberDecrementStepper,
NumberIncrementStepper,
NumberInput,
NumberInputField,
NumberIncrementStepper,
NumberDecrementStepper,
NumberInputProps,
FormLabel,
NumberInputFieldProps,
NumberInputProps,
NumberInputStepperProps,
FormControlProps,
FormLabelProps,
TooltipProps,
Tooltip,
TooltipProps,
} from '@chakra-ui/react';
import _ from 'lodash';
import { clamp } from 'lodash';
import { FocusEvent, useEffect, useState } from 'react';
const numberStringRegex = /^-?(0\.)?\.?$/;
@ -104,7 +105,7 @@ const IAINumberInput = (props: Props) => {
* clamp it on blur and floor it if needed.
*/
const handleBlur = (e: FocusEvent<HTMLInputElement>) => {
const clamped = _.clamp(
const clamped = clamp(
isInteger ? Math.floor(Number(e.target.value)) : Number(e.target.value),
min,
max

View File

@ -1,11 +1,11 @@
import {
BoxProps,
Popover,
PopoverArrow,
PopoverContent,
PopoverProps,
PopoverTrigger,
BoxProps,
} from '@chakra-ui/react';
import { PopoverProps } from '@chakra-ui/react';
import { ReactNode } from 'react';
type IAIPopoverProps = PopoverProps & {

View File

@ -23,10 +23,11 @@ import {
Tooltip,
TooltipProps,
} from '@chakra-ui/react';
import React, { FocusEvent, useMemo, useState, useEffect } from 'react';
import { clamp } from 'lodash';
import { FocusEvent, useEffect, useMemo, useState } from 'react';
import { BiReset } from 'react-icons/bi';
import IAIIconButton, { IAIIconButtonProps } from './IAIIconButton';
import _ from 'lodash';
export type IAIFullSliderProps = {
label: string;
@ -122,7 +123,7 @@ export default function IAISlider(props: IAIFullSliderProps) {
const handleInputBlur = (e: FocusEvent<HTMLInputElement>) => {
if (e.target.value === '') e.target.value = String(min);
const clamped = _.clamp(
const clamped = clamp(
isInteger ? Math.floor(Number(e.target.value)) : Number(localInputValue),
min,
numberInputMax

View File

@ -1,20 +1,20 @@
import {
useCallback,
ReactNode,
useState,
useEffect,
KeyboardEvent,
} from 'react';
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
import { FileRejection, useDropzone } from 'react-dropzone';
import { useToast } from '@chakra-ui/react';
import { ImageUploaderTriggerContext } from 'app/contexts/ImageUploaderTriggerContext';
import { activeTabNameSelector } from 'features/options/store/optionsSelectors';
import { tabDict } from 'features/tabs/components/InvokeTabs';
import ImageUploadOverlay from './ImageUploadOverlay';
import { uploadImage } from 'features/gallery/store/thunks/uploadImage';
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
import useImageUploader from 'common/hooks/useImageUploader';
import { uploadImage } from 'features/gallery/store/thunks/uploadImage';
import { tabDict } from 'features/ui/components/InvokeTabs';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import {
KeyboardEvent,
ReactNode,
useCallback,
useEffect,
useState,
} from 'react';
import { FileRejection, useDropzone } from 'react-dropzone';
import { useTranslation } from 'react-i18next';
import ImageUploadOverlay from './ImageUploadOverlay';
type ImageUploaderProps = {
children: ReactNode;
@ -33,7 +33,7 @@ const ImageUploader = (props: ImageUploaderProps) => {
(rejection: FileRejection) => {
setIsHandlingUpload(true);
const msg = rejection.errors.reduce(
(acc: string, cur: { message: string }) => acc + '\n' + cur.message,
(acc: string, cur: { message: string }) => `${acc}\n${cur.message}`,
''
);
toast({

View File

@ -1,7 +1,7 @@
import { Heading } from '@chakra-ui/react';
import { ImageUploaderTriggerContext } from 'app/contexts/ImageUploaderTriggerContext';
import { useContext } from 'react';
import { FaUpload } from 'react-icons/fa';
import { ImageUploaderTriggerContext } from 'app/contexts/ImageUploaderTriggerContext';
type ImageUploaderButtonProps = {
styleClass?: string;

View File

@ -1,6 +1,6 @@
import { ImageUploaderTriggerContext } from 'app/contexts/ImageUploaderTriggerContext';
import { useContext } from 'react';
import { FaUpload } from 'react-icons/fa';
import { ImageUploaderTriggerContext } from 'app/contexts/ImageUploaderTriggerContext';
import IAIIconButton from './IAIIconButton';
const ImageUploaderIconButton = () => {

View File

@ -1,4 +1,3 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
export default function NodesWIP() {

View File

@ -1,4 +1,3 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
export const PostProcessingWIP = () => {

View File

@ -1,4 +1,3 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
export default function TrainingWIP() {

View File

@ -1,6 +1,5 @@
import { Tooltip } from '@chakra-ui/react';
import * as Slider from '@radix-ui/react-slider';
import React from 'react';
type IAISliderProps = Slider.SliderProps & {
value: number[];

View File

@ -11,7 +11,6 @@ const useClickOutsideWatcher = () => {
function handleClickOutside(e: MouseEvent) {
watchers.forEach(({ ref, enable, callback }) => {
if (enable && ref.current && !ref.current.contains(e.target as Node)) {
console.log('callback');
callback();
}
});

View File

@ -0,0 +1,20 @@
import * as InvokeAI from 'app/invokeai';
import promptToString from './promptToString';
export function getPromptAndNegative(input_prompt: InvokeAI.Prompt) {
let prompt: string = promptToString(input_prompt);
let negativePrompt: string | null = null;
const negativePromptRegExp = new RegExp(/(?<=\[)[^\][]*(?=])/, 'gi');
const negativePromptMatches = [...prompt.matchAll(negativePromptRegExp)];
if (negativePromptMatches && negativePromptMatches.length > 0) {
negativePrompt = negativePromptMatches.join(', ');
prompt = prompt
.replaceAll(negativePromptRegExp, '')
.replaceAll('[]', '')
.trim();
}
return [prompt, negativePrompt];
}

View File

@ -1,27 +1,29 @@
import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from 'app/constants';
import { OptionsState } from 'features/options/store/optionsSlice';
import { Dimensions } from 'features/canvas/store/canvasTypes';
import { GenerationState } from 'features/parameters/store/generationSlice';
import { SystemState } from 'features/system/store/systemSlice';
import { Vector2d } from 'konva/lib/types';
import { Dimensions } from 'features/canvas/store/canvasTypes';
import { stringToSeedWeightsArray } from './seedWeightPairs';
import randomInt from './randomInt';
import { InvokeTabName } from 'features/tabs/tabMap';
import {
CanvasState,
isCanvasMaskLine,
} from 'features/canvas/store/canvasTypes';
import generateMask from 'features/canvas/util/generateMask';
import openBase64ImageInTab from './openBase64ImageInTab';
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
import type {
UpscalingLevel,
FacetoolType,
} from 'features/options/store/optionsSlice';
UpscalingLevel,
} from 'features/parameters/store/postprocessingSlice';
import { PostprocessingState } from 'features/parameters/store/postprocessingSlice';
import { InvokeTabName } from 'features/ui/store/tabMap';
import openBase64ImageInTab from './openBase64ImageInTab';
import randomInt from './randomInt';
import { stringToSeedWeightsArray } from './seedWeightPairs';
export type FrontendToBackendParametersConfig = {
generationMode: InvokeTabName;
optionsState: OptionsState;
generationState: GenerationState;
postprocessingState: PostprocessingState;
canvasState: CanvasState;
systemState: SystemState;
imageToProcessUrl?: string;
@ -91,21 +93,38 @@ export const frontendToBackendParameters = (
): BackendParameters => {
const canvasBaseLayer = getCanvasBaseLayer();
const { generationMode, optionsState, canvasState, systemState } = config;
const {
generationMode,
generationState,
postprocessingState,
canvasState,
systemState,
} = config;
const {
cfgScale,
codeformerFidelity,
facetoolStrength,
facetoolType,
height,
hiresFix,
hiresStrength,
shouldRunESRGAN,
shouldRunFacetool,
upscalingLevel,
upscalingStrength,
} = postprocessingState;
const {
cfgScale,
height,
img2imgStrength,
infillMethod,
initialImage,
iterations,
perlin,
prompt,
negativePrompt,
sampler,
seamBlur,
seamless,
@ -117,16 +136,14 @@ export const frontendToBackendParameters = (
shouldFitToWidthHeight,
shouldGenerateVariations,
shouldRandomizeSeed,
shouldRunESRGAN,
shouldRunFacetool,
steps,
threshold,
tileSize,
upscalingLevel,
upscalingStrength,
variationAmount,
width,
} = optionsState;
} = generationState;
const {
shouldDisplayInProgressType,
@ -155,6 +172,10 @@ export const frontendToBackendParameters = (
let esrganParameters: false | BackendEsrGanParameters = false;
let facetoolParameters: false | BackendFacetoolParameters = false;
if (negativePrompt !== '') {
generationParameters.prompt = `${prompt} [${negativePrompt}]`;
}
generationParameters.seed = shouldRandomizeSeed
? randomInt(NUMPY_RAND_MIN, NUMPY_RAND_MAX)
: seed;
@ -164,6 +185,8 @@ export const frontendToBackendParameters = (
generationParameters.seamless = seamless;
generationParameters.hires_fix = hiresFix;
if (hiresFix) generationParameters.strength = hiresStrength;
if (shouldRunESRGAN) {
esrganParameters = {
level: upscalingLevel,

View File

@ -63,6 +63,6 @@ export const stringToSeedWeightsArray = (
const stringPairs = string.split(',');
const arrPairs = stringPairs.map((p) => p.split(':'));
return arrPairs.map(
(p: Array<string>): Array<number> => [parseInt(p[0]), parseFloat(p[1])]
(p: Array<string>): Array<number> => [parseInt(p[0], 10), parseFloat(p[1])]
);
};

View File

@ -1,37 +1,38 @@
import { useCallback, useRef } from 'react';
import Konva from 'konva';
import { Layer, Stage } from 'react-konva';
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/storeHooks';
import {
canvasSelector,
isStagingSelector,
} from 'features/canvas/store/canvasSelectors';
import IAICanvasMaskLines from './IAICanvasMaskLines';
import IAICanvasToolPreview from './IAICanvasToolPreview';
import Konva from 'konva';
import { KonvaEventObject } from 'konva/lib/Node';
import { Vector2d } from 'konva/lib/types';
import IAICanvasBoundingBox from './IAICanvasToolbar/IAICanvasBoundingBox';
import { isEqual } from 'lodash';
import { useCallback, useRef } from 'react';
import { Layer, Stage } from 'react-konva';
import useCanvasDragMove from '../hooks/useCanvasDragMove';
import useCanvasHotkeys from '../hooks/useCanvasHotkeys';
import _ from 'lodash';
import { createSelector } from '@reduxjs/toolkit';
import IAICanvasMaskCompositer from './IAICanvasMaskCompositer';
import useCanvasWheel from '../hooks/useCanvasZoom';
import useCanvasMouseDown from '../hooks/useCanvasMouseDown';
import useCanvasMouseUp from '../hooks/useCanvasMouseUp';
import useCanvasMouseMove from '../hooks/useCanvasMouseMove';
import useCanvasMouseOut from '../hooks/useCanvasMouseOut';
import useCanvasDragMove from '../hooks/useCanvasDragMove';
import IAICanvasObjectRenderer from './IAICanvasObjectRenderer';
import IAICanvasGrid from './IAICanvasGrid';
import IAICanvasIntermediateImage from './IAICanvasIntermediateImage';
import IAICanvasStatusText from './IAICanvasStatusText';
import IAICanvasStagingArea from './IAICanvasStagingArea';
import IAICanvasStagingAreaToolbar from './IAICanvasStagingAreaToolbar';
import useCanvasMouseUp from '../hooks/useCanvasMouseUp';
import useCanvasWheel from '../hooks/useCanvasZoom';
import {
setCanvasBaseLayer,
setCanvasStage,
} from '../util/konvaInstanceProvider';
import { KonvaEventObject } from 'konva/lib/Node';
import IAICanvasBoundingBoxOverlay from './IAICanvasBoundingBoxOverlay';
import IAICanvasGrid from './IAICanvasGrid';
import IAICanvasIntermediateImage from './IAICanvasIntermediateImage';
import IAICanvasMaskCompositer from './IAICanvasMaskCompositer';
import IAICanvasMaskLines from './IAICanvasMaskLines';
import IAICanvasObjectRenderer from './IAICanvasObjectRenderer';
import IAICanvasStagingArea from './IAICanvasStagingArea';
import IAICanvasStagingAreaToolbar from './IAICanvasStagingAreaToolbar';
import IAICanvasStatusText from './IAICanvasStatusText';
import IAICanvasBoundingBox from './IAICanvasToolbar/IAICanvasBoundingBox';
import IAICanvasToolPreview from './IAICanvasToolPreview';
const selector = createSelector(
[canvasSelector, isStagingSelector],
@ -82,7 +83,7 @@ const selector = createSelector(
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
resultEqualityCheck: isEqual,
},
}
);

View File

@ -1,6 +1,7 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/storeHooks';
import _ from 'lodash';
import { isEqual } from 'lodash';
import { Group, Rect } from 'react-konva';
import { canvasSelector } from '../store/canvasSelectors';
@ -27,7 +28,7 @@ const selector = createSelector(
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
resultEqualityCheck: isEqual,
},
}
);

View File

@ -3,10 +3,11 @@
import { useColorMode } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/storeHooks';
import _ from 'lodash';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import { isEqual, range } from 'lodash';
import { ReactNode, useCallback, useLayoutEffect, useState } from 'react';
import { Group, Line as KonvaLine } from 'react-konva';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
const selector = createSelector(
[canvasSelector],
@ -16,7 +17,7 @@ const selector = createSelector(
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
resultEqualityCheck: isEqual,
},
}
);
@ -85,7 +86,7 @@ const IAICanvasGrid = () => {
xSteps = Math.round(xSize / 64) + 1,
ySteps = Math.round(ySize / 64) + 1;
const xLines = _.range(0, xSteps).map((i) => (
const xLines = range(0, xSteps).map((i) => (
<KonvaLine
key={`x_${i}`}
x={fullRect.x1 + i * 64}
@ -95,7 +96,7 @@ const IAICanvasGrid = () => {
strokeWidth={1}
/>
));
const yLines = _.range(0, ySteps).map((i) => (
const yLines = range(0, ySteps).map((i) => (
<KonvaLine
key={`y_${i}`}
x={fullRect.x1}

View File

@ -3,7 +3,8 @@ import { RootState } from 'app/store';
import { useAppSelector } from 'app/storeHooks';
import { GalleryState } from 'features/gallery/store/gallerySlice';
import { ImageConfig } from 'konva/lib/shapes/Image';
import _ from 'lodash';
import { isEqual } from 'lodash';
import { useEffect, useState } from 'react';
import { Image as KonvaImage } from 'react-konva';
@ -14,7 +15,7 @@ const selector = createSelector(
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
resultEqualityCheck: isEqual,
},
}
);

View File

@ -1,13 +1,13 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/storeHooks';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import { RectConfig } from 'konva/lib/shapes/Rect';
import { Rect } from 'react-konva';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import { rgbaColorToString } from 'features/canvas/util/colorToString';
import { useCallback, useEffect, useRef, useState } from 'react';
import Konva from 'konva';
import { isNumber } from 'lodash';
import { useCallback, useEffect, useRef, useState } from 'react';
export const canvasMaskCompositerSelector = createSelector(
canvasSelector,

View File

@ -1,10 +1,11 @@
import { GroupConfig } from 'konva/lib/Group';
import { Group, Line } from 'react-konva';
import { useAppSelector } from 'app/storeHooks';
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/storeHooks';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import { GroupConfig } from 'konva/lib/Group';
import { isEqual } from 'lodash';
import { Group, Line } from 'react-konva';
import { isCanvasMaskLine } from '../store/canvasTypes';
import _ from 'lodash';
export const canvasLinesSelector = createSelector(
[canvasSelector],
@ -13,7 +14,7 @@ export const canvasLinesSelector = createSelector(
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
resultEqualityCheck: isEqual,
},
}
);

View File

@ -1,6 +1,9 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/storeHooks';
import _ from 'lodash';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import { rgbaColorToString } from 'features/canvas/util/colorToString';
import { isEqual } from 'lodash';
import { Group, Line, Rect } from 'react-konva';
import {
isCanvasBaseImage,
@ -9,8 +12,6 @@ import {
isCanvasFillRect,
} from '../store/canvasTypes';
import IAICanvasImage from './IAICanvasImage';
import { rgbaColorToString } from 'features/canvas/util/colorToString';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
const selector = createSelector(
[canvasSelector],
@ -24,7 +25,7 @@ const selector = createSelector(
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
resultEqualityCheck: isEqual,
},
}
);

View File

@ -1,18 +1,18 @@
import { Spinner } from '@chakra-ui/react';
import { useLayoutEffect, useRef } from 'react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
import { activeTabNameSelector } from 'features/options/store/optionsSelectors';
import {
canvasSelector,
initialCanvasImageSelector,
} from 'features/canvas/store/canvasSelectors';
import {
resizeAndScaleCanvas,
resizeCanvas,
setCanvasContainerDimensions,
setDoesCanvasNeedScaling,
} from 'features/canvas/store/canvasSlice';
import { createSelector } from '@reduxjs/toolkit';
import {
canvasSelector,
initialCanvasImageSelector,
} from 'features/canvas/store/canvasSelectors';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { useLayoutEffect, useRef } from 'react';
const canvasResizerSelector = createSelector(
canvasSelector,

View File

@ -1,9 +1,10 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/storeHooks';
import { GroupConfig } from 'konva/lib/Group';
import _ from 'lodash';
import { Group, Rect } from 'react-konva';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import { GroupConfig } from 'konva/lib/Group';
import { isEqual } from 'lodash';
import { Group, Rect } from 'react-konva';
import IAICanvasImage from './IAICanvasImage';
const selector = createSelector(
@ -34,7 +35,7 @@ const selector = createSelector(
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
resultEqualityCheck: isEqual,
},
}
);

View File

@ -1,18 +1,8 @@
import { ButtonGroup, Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { saveStagingAreaImageToGallery } from 'app/socketio/actions';
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
import IAIIconButton from 'common/components/IAIIconButton';
import _ from 'lodash';
import { useCallback } from 'react';
import {
FaArrowLeft,
FaArrowRight,
FaCheck,
FaEye,
FaEyeSlash,
FaPlus,
FaSave,
} from 'react-icons/fa';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import {
commitStagingAreaImage,
@ -22,9 +12,20 @@ import {
setShouldShowStagingImage,
setShouldShowStagingOutline,
} from 'features/canvas/store/canvasSlice';
import { isEqual } from 'lodash';
import { useCallback } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { saveStagingAreaImageToGallery } from 'app/socketio/actions';
import { useTranslation } from 'react-i18next';
import {
FaArrowLeft,
FaArrowRight,
FaCheck,
FaEye,
FaEyeSlash,
FaPlus,
FaSave,
} from 'react-icons/fa';
const selector = createSelector(
[canvasSelector],
@ -48,7 +49,7 @@ const selector = createSelector(
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
resultEqualityCheck: isEqual,
},
}
);

View File

@ -1,10 +1,11 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/storeHooks';
import _ from 'lodash';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import IAICanvasStatusTextCursorPos from './IAICanvasStatusText/IAICanvasStatusTextCursorPos';
import roundToHundreth from '../util/roundToHundreth';
import { isEqual } from 'lodash';
import { useTranslation } from 'react-i18next';
import roundToHundreth from '../util/roundToHundreth';
import IAICanvasStatusTextCursorPos from './IAICanvasStatusText/IAICanvasStatusTextCursorPos';
const selector = createSelector(
[canvasSelector],
@ -59,7 +60,7 @@ const selector = createSelector(
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
resultEqualityCheck: isEqual,
},
}
);

View File

@ -1,9 +1,9 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/storeHooks';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import React from 'react';
import _ from 'lodash';
import roundToHundreth from 'features/canvas/util/roundToHundreth';
import { isEqual } from 'lodash';
import { useTranslation } from 'react-i18next';
const cursorPositionSelector = createSelector(
@ -23,7 +23,7 @@ const cursorPositionSelector = createSelector(
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
resultEqualityCheck: isEqual,
},
}
);

View File

@ -1,10 +1,11 @@
import { createSelector } from '@reduxjs/toolkit';
import { GroupConfig } from 'konva/lib/Group';
import _ from 'lodash';
import { Circle, Group } from 'react-konva';
import { useAppSelector } from 'app/storeHooks';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import { rgbaColorToString } from 'features/canvas/util/colorToString';
import { GroupConfig } from 'konva/lib/Group';
import { isEqual } from 'lodash';
import { Circle, Group } from 'react-konva';
import {
COLOR_PICKER_SIZE,
COLOR_PICKER_STROKE_RADIUS,
@ -106,7 +107,7 @@ const canvasBrushPreviewSelector = createSelector(
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
resultEqualityCheck: isEqual,
},
}
);

View File

@ -1,10 +1,4 @@
import { createSelector } from '@reduxjs/toolkit';
import Konva from 'konva';
import { KonvaEventObject } from 'konva/lib/Node';
import { Vector2d } from 'konva/lib/types';
import _ from 'lodash';
import { useCallback, useEffect, useRef, useState } from 'react';
import { Group, Rect, Transformer } from 'react-konva';
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
import {
roundDownToMultiple,
@ -18,7 +12,14 @@ import {
setIsMovingBoundingBox,
setIsTransformingBoundingBox,
} from 'features/canvas/store/canvasSlice';
import Konva from 'konva';
import { GroupConfig } from 'konva/lib/Group';
import { KonvaEventObject } from 'konva/lib/Node';
import { Vector2d } from 'konva/lib/types';
import { isEqual } from 'lodash';
import { useCallback, useEffect, useRef, useState } from 'react';
import { Group, Rect, Transformer } from 'react-konva';
const boundingBoxPreviewSelector = createSelector(
canvasSelector,
@ -48,7 +49,7 @@ const boundingBoxPreviewSelector = createSelector(
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
resultEqualityCheck: isEqual,
},
}
);

View File

@ -1,5 +1,15 @@
import { ButtonGroup, Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
import IAIButton from 'common/components/IAIButton';
import IAICheckbox from 'common/components/IAICheckbox';
import IAIColorPicker from 'common/components/IAIColorPicker';
import IAIIconButton from 'common/components/IAIIconButton';
import IAIPopover from 'common/components/IAIPopover';
import {
canvasSelector,
isStagingSelector,
} from 'features/canvas/store/canvasSelectors';
import {
clearMask,
setIsMaskEnabled,
@ -7,21 +17,12 @@ import {
setMaskColor,
setShouldPreserveMaskedArea,
} from 'features/canvas/store/canvasSlice';
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
import _ from 'lodash';
import IAIIconButton from 'common/components/IAIIconButton';
import { FaMask, FaTrash } from 'react-icons/fa';
import IAIPopover from 'common/components/IAIPopover';
import IAICheckbox from 'common/components/IAICheckbox';
import IAIColorPicker from 'common/components/IAIColorPicker';
import IAIButton from 'common/components/IAIButton';
import {
canvasSelector,
isStagingSelector,
} from 'features/canvas/store/canvasSelectors';
import { useHotkeys } from 'react-hotkeys-hook';
import { rgbaColorToString } from 'features/canvas/util/colorToString';
import { isEqual } from 'lodash';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { FaMask, FaTrash } from 'react-icons/fa';
export const selector = createSelector(
[canvasSelector, isStagingSelector],
@ -40,7 +41,7 @@ export const selector = createSelector(
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
resultEqualityCheck: isEqual,
},
}
);

View File

@ -1,14 +1,15 @@
import { createSelector } from '@reduxjs/toolkit';
import { useHotkeys } from 'react-hotkeys-hook';
import { FaRedo } from 'react-icons/fa';
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
import IAIIconButton from 'common/components/IAIIconButton';
import { activeTabNameSelector } from 'features/options/store/optionsSelectors';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { useHotkeys } from 'react-hotkeys-hook';
import { FaRedo } from 'react-icons/fa';
import _ from 'lodash';
import { redo } from 'features/canvas/store/canvasSlice';
import { systemSelector } from 'features/system/store/systemSelectors';
import { isEqual } from 'lodash';
import { useTranslation } from 'react-i18next';
const canvasRedoSelector = createSelector(
@ -23,7 +24,7 @@ const canvasRedoSelector = createSelector(
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
resultEqualityCheck: isEqual,
},
}
);

View File

@ -1,5 +1,10 @@
import { Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
import IAICheckbox from 'common/components/IAICheckbox';
import IAIIconButton from 'common/components/IAIIconButton';
import IAIPopover from 'common/components/IAIPopover';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import {
setShouldAutoSave,
setShouldCropToBoundingBoxOnSave,
@ -10,18 +15,14 @@ import {
setShouldShowIntermediates,
setShouldSnapToGrid,
} from 'features/canvas/store/canvasSlice';
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
import _ from 'lodash';
import IAIIconButton from 'common/components/IAIIconButton';
import { FaWrench } from 'react-icons/fa';
import IAIPopover from 'common/components/IAIPopover';
import IAICheckbox from 'common/components/IAICheckbox';
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
import EmptyTempFolderButtonModal from 'features/system/components/ClearTempFolderButtonModal';
import ClearCanvasHistoryButtonModal from '../ClearCanvasHistoryButtonModal';
import { isEqual } from 'lodash';
import { ChangeEvent } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { FaWrench } from 'react-icons/fa';
import ClearCanvasHistoryButtonModal from '../ClearCanvasHistoryButtonModal';
export const canvasControlsSelector = createSelector(
[canvasSelector],
@ -50,7 +51,7 @@ export const canvasControlsSelector = createSelector(
},
{
memoizeOptions: {
resultEqualityCheck: _.isEqual,
resultEqualityCheck: isEqual,
},
}
);

Some files were not shown because too many files have changed in this diff Show More