From cab8239ba878b2fc87be4ec4da206f3f718ea796 Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Mon, 14 Aug 2023 20:18:09 -0400 Subject: [PATCH 01/87] add get_logger() as alias for getLogger() --- invokeai/backend/util/logging.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/invokeai/backend/util/logging.py b/invokeai/backend/util/logging.py index 3a8d721aa5..5c511bcab7 100644 --- a/invokeai/backend/util/logging.py +++ b/invokeai/backend/util/logging.py @@ -228,7 +228,6 @@ def basicConfig(**kwargs): def getLogger(name: str = None) -> logging.Logger: return InvokeAILogger.getLogger(name) - _FACILITY_MAP = ( dict( LOG_KERN=syslog.LOG_KERN, @@ -366,6 +365,11 @@ class InvokeAILogger(object): cls.loggers[name] = logger return cls.loggers[name] + # same thing without the camel case + @classmethod + def get_logger(cls, *arg, **kwarg) -> logging.Logger: + return cls.getLogger(*arg, **kwarg) + @classmethod def getLoggers(cls, config: InvokeAIAppConfig) -> list[logging.Handler]: handler_strs = config.log_handlers From 09ef57718e4ddcee7fe6cf715ddd16523f916919 Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Mon, 14 Aug 2023 20:20:35 -0400 Subject: [PATCH 02/87] fix docs --- invokeai/backend/util/logging.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/invokeai/backend/util/logging.py b/invokeai/backend/util/logging.py index 5c511bcab7..78634eee16 100644 --- a/invokeai/backend/util/logging.py +++ b/invokeai/backend/util/logging.py @@ -1,7 +1,6 @@ # Copyright (c) 2023 Lincoln D. Stein and The InvokeAI Development Team -""" -invokeai.backend.util.logging +"""invokeai.backend.util.logging Logging class for InvokeAI that produces console messages @@ -40,7 +39,10 @@ object: config = InvokeAIAppConfig.get_config() config.parse_args() - logger = InvokeAILogger.getLogger(config=config) + logger = InvokeAILogger.get_logger(config=config) + +For backward compatibility, getLogger() is an alias for get_logger(), +but without the camel case. ### Three command-line options control logging: @@ -173,6 +175,7 @@ InvokeAI: log_level: info log_format: color ``` + """ import logging.handlers @@ -228,6 +231,7 @@ def basicConfig(**kwargs): def getLogger(name: str = None) -> logging.Logger: return InvokeAILogger.getLogger(name) + _FACILITY_MAP = ( dict( LOG_KERN=syslog.LOG_KERN, From 1d107f30e5992bdbe9d31ee17523329024577cd7 Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Thu, 17 Aug 2023 19:17:38 -0400 Subject: [PATCH 03/87] remove getLogger() completely --- invokeai/app/api/dependencies.py | 2 +- invokeai/app/api_app.py | 4 +- invokeai/app/cli_app.py | 2 +- .../backend/install/invokeai_configure.py | 4 +- .../backend/install/model_install_backend.py | 4 +- .../convert_ckpt_to_diffusers.py | 2 +- invokeai/backend/util/logging.py | 40 +++++++------------ invokeai/frontend/install/model_install.py | 6 +-- 8 files changed, 26 insertions(+), 38 deletions(-) diff --git a/invokeai/app/api/dependencies.py b/invokeai/app/api/dependencies.py index 4aaf7a0272..3683d812e9 100644 --- a/invokeai/app/api/dependencies.py +++ b/invokeai/app/api/dependencies.py @@ -49,7 +49,7 @@ def check_internet() -> bool: return False -logger = InvokeAILogger.getLogger() +logger = InvokeAILogger.get_logger() class ApiDependencies: diff --git a/invokeai/app/api_app.py b/invokeai/app/api_app.py index 20b2781ef0..22e9d5ed40 100644 --- a/invokeai/app/api_app.py +++ b/invokeai/app/api_app.py @@ -23,7 +23,7 @@ from ..backend.util.logging import InvokeAILogger app_config = InvokeAIAppConfig.get_config() app_config.parse_args() -logger = InvokeAILogger.getLogger(config=app_config) +logger = InvokeAILogger.get_logger(config=app_config) from invokeai.version.invokeai_version import __version__ # we call this early so that the message appears before @@ -230,7 +230,7 @@ def invoke_api(): # replace uvicorn's loggers with InvokeAI's for consistent appearance for logname in ["uvicorn.access", "uvicorn"]: - l = logging.getLogger(logname) + l = logging.get_logger(logname) l.handlers.clear() for ch in logger.handlers: l.addHandler(ch) diff --git a/invokeai/app/cli_app.py b/invokeai/app/cli_app.py index 4558c9219f..ae05ee9fc6 100644 --- a/invokeai/app/cli_app.py +++ b/invokeai/app/cli_app.py @@ -16,7 +16,7 @@ from invokeai.backend.util.logging import InvokeAILogger config = InvokeAIAppConfig.get_config() config.parse_args() -logger = InvokeAILogger().getLogger(config=config) +logger = InvokeAILogger().get_logger(config=config) from invokeai.version.invokeai_version import __version__ # we call this early so that the message appears before other invokeai initialization messages diff --git a/invokeai/backend/install/invokeai_configure.py b/invokeai/backend/install/invokeai_configure.py index 6996b913c2..be7ff8a306 100755 --- a/invokeai/backend/install/invokeai_configure.py +++ b/invokeai/backend/install/invokeai_configure.py @@ -96,7 +96,7 @@ INIT_FILE_PREAMBLE = """# InvokeAI initialization file # or renaming it and then running invokeai-configure again. """ -logger = InvokeAILogger.getLogger() +logger = InvokeAILogger.get_logger() class DummyWidgetValue(Enum): @@ -827,7 +827,7 @@ def main(): if opt.full_precision: invoke_args.extend(["--precision", "float32"]) config.parse_args(invoke_args) - logger = InvokeAILogger().getLogger(config=config) + logger = InvokeAILogger().get_logger(config=config) errors = set() diff --git a/invokeai/backend/install/model_install_backend.py b/invokeai/backend/install/model_install_backend.py index 3a6d879bee..798345e5bf 100644 --- a/invokeai/backend/install/model_install_backend.py +++ b/invokeai/backend/install/model_install_backend.py @@ -31,7 +31,7 @@ warnings.filterwarnings("ignore") # --------------------------globals----------------------- config = InvokeAIAppConfig.get_config() -logger = InvokeAILogger.getLogger(name="InvokeAI") +logger = InvokeAILogger.get_logger(name="InvokeAI") # the initial "configs" dir is now bundled in the `invokeai.configs` package Dataset_path = Path(configs.__path__[0]) / "INITIAL_MODELS.yaml" @@ -483,7 +483,7 @@ def yes_or_no(prompt: str, default_yes=True): # --------------------------------------------- def hf_download_from_pretrained(model_class: object, model_name: str, destination: Path, **kwargs): - logger = InvokeAILogger.getLogger("InvokeAI") + logger = InvokeAILogger.get_logger("InvokeAI") logger.addFilter(lambda x: "fp16 is not a valid" not in x.getMessage()) model = model_class.from_pretrained( diff --git a/invokeai/backend/model_management/convert_ckpt_to_diffusers.py b/invokeai/backend/model_management/convert_ckpt_to_diffusers.py index 5fd3669911..ae41700b69 100644 --- a/invokeai/backend/model_management/convert_ckpt_to_diffusers.py +++ b/invokeai/backend/model_management/convert_ckpt_to_diffusers.py @@ -80,7 +80,7 @@ if is_accelerate_available(): from accelerate import init_empty_weights from accelerate.utils import set_module_tensor_to_device -logger = InvokeAILogger.getLogger(__name__) +logger = InvokeAILogger.get_logger(__name__) CONVERT_MODEL_ROOT = InvokeAIAppConfig.get_config().models_path / "core/convert" diff --git a/invokeai/backend/util/logging.py b/invokeai/backend/util/logging.py index 78634eee16..efd2689b1c 100644 --- a/invokeai/backend/util/logging.py +++ b/invokeai/backend/util/logging.py @@ -8,9 +8,9 @@ Usage: from invokeai.backend.util.logging import InvokeAILogger -logger = InvokeAILogger.getLogger(name='InvokeAI') // Initialization +logger = InvokeAILogger.get_logger(name='InvokeAI') // Initialization (or) -logger = InvokeAILogger.getLogger(__name__) // To use the filename +logger = InvokeAILogger.get_logger(__name__) // To use the filename logger.configure() logger.critical('this is critical') // Critical Message @@ -33,7 +33,7 @@ IAILogger.debug('this is a debugging message') ## Configuration The default configuration will print to stderr on the console. To add -additional logging handlers, call getLogger with an initialized InvokeAIAppConfig +additional logging handlers, call get_logger with an initialized InvokeAIAppConfig object: @@ -41,9 +41,6 @@ object: config.parse_args() logger = InvokeAILogger.get_logger(config=config) -For backward compatibility, getLogger() is an alias for get_logger(), -but without the camel case. - ### Three command-line options control logging: `--log_handlers ...` @@ -197,39 +194,35 @@ except: # module level functions def debug(msg, *args, **kwargs): - InvokeAILogger.getLogger().debug(msg, *args, **kwargs) + InvokeAILogger.get_logger().debug(msg, *args, **kwargs) def info(msg, *args, **kwargs): - InvokeAILogger.getLogger().info(msg, *args, **kwargs) + InvokeAILogger.get_logger().info(msg, *args, **kwargs) def warning(msg, *args, **kwargs): - InvokeAILogger.getLogger().warning(msg, *args, **kwargs) + InvokeAILogger.get_logger().warning(msg, *args, **kwargs) def error(msg, *args, **kwargs): - InvokeAILogger.getLogger().error(msg, *args, **kwargs) + InvokeAILogger.get_logger().error(msg, *args, **kwargs) def critical(msg, *args, **kwargs): - InvokeAILogger.getLogger().critical(msg, *args, **kwargs) + InvokeAILogger.get_logger().critical(msg, *args, **kwargs) def log(level, msg, *args, **kwargs): - InvokeAILogger.getLogger().log(level, msg, *args, **kwargs) + InvokeAILogger.get_logger().log(level, msg, *args, **kwargs) def disable(level=logging.CRITICAL): - InvokeAILogger.getLogger().disable(level) + InvokeAILogger.get_logger().disable(level) def basicConfig(**kwargs): - InvokeAILogger.getLogger().basicConfig(**kwargs) - - -def getLogger(name: str = None) -> logging.Logger: - return InvokeAILogger.getLogger(name) + InvokeAILogger.get_logger().basicConfig(**kwargs) _FACILITY_MAP = ( @@ -355,7 +348,7 @@ class InvokeAILogger(object): loggers = dict() @classmethod - def getLogger( + def get_logger( cls, name: str = "InvokeAI", config: InvokeAIAppConfig = InvokeAIAppConfig.get_config() ) -> logging.Logger: if name in cls.loggers: @@ -364,18 +357,13 @@ class InvokeAILogger(object): else: logger = logging.getLogger(name) logger.setLevel(config.log_level.upper()) # yes, strings work here - for ch in cls.getLoggers(config): + for ch in cls.get_loggers(config): logger.addHandler(ch) cls.loggers[name] = logger return cls.loggers[name] - # same thing without the camel case @classmethod - def get_logger(cls, *arg, **kwarg) -> logging.Logger: - return cls.getLogger(*arg, **kwarg) - - @classmethod - def getLoggers(cls, config: InvokeAIAppConfig) -> list[logging.Handler]: + def get_loggers(cls, config: InvokeAIAppConfig) -> list[logging.Handler]: handler_strs = config.log_handlers handlers = list() for handler in handler_strs: diff --git a/invokeai/frontend/install/model_install.py b/invokeai/frontend/install/model_install.py index ade3043d96..1153ea313e 100644 --- a/invokeai/frontend/install/model_install.py +++ b/invokeai/frontend/install/model_install.py @@ -50,7 +50,7 @@ from invokeai.frontend.install.widgets import ( from invokeai.app.services.config import InvokeAIAppConfig config = InvokeAIAppConfig.get_config() -logger = InvokeAILogger.getLogger() +logger = InvokeAILogger.get_logger() # build a table mapping all non-printable characters to None # for stripping control characters @@ -657,7 +657,7 @@ def process_and_execute( translator = StderrToMessage(conn_out) sys.stderr = translator sys.stdout = translator - logger = InvokeAILogger.getLogger() + logger = InvokeAILogger.get_logger() logger.handlers.clear() logger.addHandler(logging.StreamHandler(translator)) @@ -771,7 +771,7 @@ def main(): if opt.full_precision: invoke_args.extend(["--precision", "float32"]) config.parse_args(invoke_args) - logger = InvokeAILogger().getLogger(config=config) + logger = InvokeAILogger().get_logger(config=config) if not config.model_conf_path.exists(): logger.info("Your InvokeAI root directory is not set up. Calling invokeai-configure.") From 4570702dd0a220b5856ef6414f653d7b52c25a81 Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Thu, 17 Aug 2023 20:17:10 -0400 Subject: [PATCH 04/87] hotfix for crashing api --- invokeai/app/api_app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/app/api_app.py b/invokeai/app/api_app.py index 22e9d5ed40..dab3dac2c0 100644 --- a/invokeai/app/api_app.py +++ b/invokeai/app/api_app.py @@ -230,7 +230,7 @@ def invoke_api(): # replace uvicorn's loggers with InvokeAI's for consistent appearance for logname in ["uvicorn.access", "uvicorn"]: - l = logging.get_logger(logname) + l = logging.getLogger(logname) l.handlers.clear() for ch in logger.handlers: l.addHandler(ch) From 58aa159a501fe38dbf8bdf308d4d5edaffbf541a Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 5 Sep 2023 10:43:30 +1000 Subject: [PATCH 05/87] fix(backend): fix remaining instances of `getLogger()` --- invokeai/app/api_app.py | 5 ++--- invokeai/backend/util/hotfixes.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/invokeai/app/api_app.py b/invokeai/app/api_app.py index 967fc0f960..a0b381477b 100644 --- a/invokeai/app/api_app.py +++ b/invokeai/app/api_app.py @@ -1,6 +1,5 @@ # Copyright (c) 2022-2023 Kyle Schouviller (https://github.com/kyle0654) and the InvokeAI Team import asyncio -import logging import socket from inspect import signature from pathlib import Path @@ -218,7 +217,7 @@ def invoke_api(): exc_info=e, ) else: - jurigged.watch(logger=InvokeAILogger.getLogger(name="jurigged").info) + jurigged.watch(logger=InvokeAILogger.get_logger(name="jurigged").info) port = find_port(app_config.port) if port != app_config.port: @@ -237,7 +236,7 @@ def invoke_api(): # replace uvicorn's loggers with InvokeAI's for consistent appearance for logname in ["uvicorn.access", "uvicorn"]: - log = logging.getLogger(logname) + log = InvokeAILogger.get_logger(logname) log.handlers.clear() for ch in logger.handlers: log.addHandler(ch) diff --git a/invokeai/backend/util/hotfixes.py b/invokeai/backend/util/hotfixes.py index 983d0b7601..42ca5d08ee 100644 --- a/invokeai/backend/util/hotfixes.py +++ b/invokeai/backend/util/hotfixes.py @@ -24,7 +24,7 @@ from invokeai.backend.util.logging import InvokeAILogger # Modified ControlNetModel with encoder_attention_mask argument added -logger = InvokeAILogger.getLogger(__name__) +logger = InvokeAILogger.get_logger(__name__) class ControlNetModel(ModelMixin, ConfigMixin, FromOriginalControlnetMixin): From 1625854eaf51aab68f5348610e36821ffd3c2d5a Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 21 Sep 2023 11:43:05 +1000 Subject: [PATCH 06/87] fix(nodes): fix ip-adapter field positioning on workflow editor --- invokeai/app/invocations/ip_adapter.py | 4 +--- invokeai/frontend/web/src/features/nodes/types/constants.ts | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/invokeai/app/invocations/ip_adapter.py b/invokeai/app/invocations/ip_adapter.py index 0c5b858112..3e3a3d9b1f 100644 --- a/invokeai/app/invocations/ip_adapter.py +++ b/invokeai/app/invocations/ip_adapter.py @@ -58,9 +58,7 @@ class IPAdapterInvocation(BaseInvocation): # Inputs image: ImageField = InputField(description="The IP-Adapter image prompt.") ip_adapter_model: IPAdapterModelField = InputField( - description="The IP-Adapter model.", - title="IP-Adapter Model", - input=Input.Direct, + description="The IP-Adapter model.", title="IP-Adapter Model", input=Input.Direct, ui_order=-1 ) # weight: float = InputField(default=1.0, description="The weight of the IP-Adapter.", ui_type=UIType.Float) diff --git a/invokeai/frontend/web/src/features/nodes/types/constants.ts b/invokeai/frontend/web/src/features/nodes/types/constants.ts index a54f84d3f0..92a6a32e3a 100644 --- a/invokeai/frontend/web/src/features/nodes/types/constants.ts +++ b/invokeai/frontend/web/src/features/nodes/types/constants.ts @@ -116,6 +116,7 @@ export const TYPES_WITH_INPUT_COMPONENTS = [ 'ColorField', 'SDXLMainModelField', 'Scheduler', + 'IPAdapterModelField', ]; export const isPolymorphicItemType = ( From 28e6a7139b7e8c2c84409cc47d3e13505bd95005 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 21 Sep 2023 13:07:15 +1000 Subject: [PATCH 07/87] fix(ui): add control adapters to canvas coherence pass --- .../graphBuilders/addControlNetToLinearGraph.ts | 16 +++++++++++++++- .../graphBuilders/addIPAdapterToLinearGraph.ts | 12 +++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addControlNetToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addControlNetToLinearGraph.ts index 491c6547ba..1df90624ef 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addControlNetToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addControlNetToLinearGraph.ts @@ -8,7 +8,11 @@ import { MetadataAccumulatorInvocation, } from 'services/api/types'; import { NonNullableGraph } from '../../types/types'; -import { CONTROL_NET_COLLECT, METADATA_ACCUMULATOR } from './constants'; +import { + CANVAS_COHERENCE_DENOISE_LATENTS, + CONTROL_NET_COLLECT, + METADATA_ACCUMULATOR, +} from './constants'; export const addControlNetToLinearGraph = ( state: RootState, @@ -100,6 +104,16 @@ export const addControlNetToLinearGraph = ( field: 'item', }, }); + + if (CANVAS_COHERENCE_DENOISE_LATENTS in graph.nodes) { + graph.edges.push({ + source: { node_id: controlNetNode.id, field: 'control' }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'control', + }, + }); + } }); } } diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts index da67b1d34d..d645b274ec 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts @@ -1,7 +1,7 @@ import { RootState } from 'app/store/store'; import { IPAdapterInvocation } from 'services/api/types'; import { NonNullableGraph } from '../../types/types'; -import { IP_ADAPTER } from './constants'; +import { CANVAS_COHERENCE_DENOISE_LATENTS, IP_ADAPTER } from './constants'; export const addIPAdapterToLinearGraph = ( state: RootState, @@ -55,5 +55,15 @@ export const addIPAdapterToLinearGraph = ( field: 'ip_adapter', }, }); + + if (CANVAS_COHERENCE_DENOISE_LATENTS in graph.nodes) { + graph.edges.push({ + source: { node_id: ipAdapterNode.id, field: 'ip_adapter' }, + destination: { + node_id: CANVAS_COHERENCE_DENOISE_LATENTS, + field: 'ip_adapter', + }, + }); + } } }; From 02c087ee37e711ece610b7c6aef30108b0ba76bb Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 21 Sep 2023 14:10:44 +1000 Subject: [PATCH 08/87] feat(ui): hide clipskip on sdxl; do not add to metadata Hide it until #4624 is ready --- .../buildCanvasSDXLImageToImageGraph.ts | 2 -- .../buildCanvasSDXLTextToImageGraph.ts | 2 -- .../buildLinearSDXLImageToImageGraph.ts | 2 -- .../buildLinearSDXLTextToImageGraph.ts | 2 -- .../Advanced/ParamAdvancedCollapse.tsx | 18 +++++++++++------- .../Parameters/Advanced/ParamClipSkip.tsx | 4 ++++ 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts index 36fc66e559..d958b78a90 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLImageToImageGraph.ts @@ -45,7 +45,6 @@ export const buildCanvasSDXLImageToImageGraph = ( seed, steps, vaePrecision, - clipSkip, shouldUseCpuNoise, seamlessXAxis, seamlessYAxis, @@ -339,7 +338,6 @@ export const buildCanvasSDXLImageToImageGraph = ( vae: undefined, // option; set in addVAEToGraph controlnets: [], // populated in addControlNetToLinearGraph loras: [], // populated in addLoRAsToGraph - clip_skip: clipSkip, strength, init_image: initialImage.image_name, }; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts index 37245d7b6a..9f9a442b99 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildCanvasSDXLTextToImageGraph.ts @@ -46,7 +46,6 @@ export const buildCanvasSDXLTextToImageGraph = ( seed, steps, vaePrecision, - clipSkip, shouldUseCpuNoise, seamlessXAxis, seamlessYAxis, @@ -321,7 +320,6 @@ export const buildCanvasSDXLTextToImageGraph = ( vae: undefined, // option; set in addVAEToGraph controlnets: [], // populated in addControlNetToLinearGraph loras: [], // populated in addLoRAsToGraph - clip_skip: clipSkip, }; graph.edges.push({ diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts index b10f4c5542..bc02fb5a66 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLImageToImageGraph.ts @@ -49,7 +49,6 @@ export const buildLinearSDXLImageToImageGraph = ( shouldFitToWidthHeight, width, height, - clipSkip, shouldUseCpuNoise, vaePrecision, seamlessXAxis, @@ -349,7 +348,6 @@ export const buildLinearSDXLImageToImageGraph = ( vae: undefined, controlnets: [], loras: [], - clip_skip: clipSkip, strength: strength, init_image: initialImage.imageName, positive_style_prompt: positiveStylePrompt, diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts index 73c831081d..22a7dd4192 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildLinearSDXLTextToImageGraph.ts @@ -38,7 +38,6 @@ export const buildLinearSDXLTextToImageGraph = ( steps, width, height, - clipSkip, shouldUseCpuNoise, vaePrecision, seamlessXAxis, @@ -243,7 +242,6 @@ export const buildLinearSDXLTextToImageGraph = ( vae: undefined, controlnets: [], loras: [], - clip_skip: clipSkip, positive_style_prompt: positiveStylePrompt, negative_style_prompt: negativeStylePrompt, }; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse.tsx index dea4bb7b3d..85b6eaa903 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse.tsx @@ -13,16 +13,16 @@ import ParamClipSkip from './ParamClipSkip'; const selector = createSelector( stateSelector, (state: RootState) => { - const { clipSkip, seamlessXAxis, seamlessYAxis, shouldUseCpuNoise } = + const { clipSkip, model, seamlessXAxis, seamlessYAxis, shouldUseCpuNoise } = state.generation; - return { clipSkip, seamlessXAxis, seamlessYAxis, shouldUseCpuNoise }; + return { clipSkip, model, seamlessXAxis, seamlessYAxis, shouldUseCpuNoise }; }, defaultSelectorOptions ); export default function ParamAdvancedCollapse() { - const { clipSkip, seamlessXAxis, seamlessYAxis, shouldUseCpuNoise } = + const { clipSkip, model, seamlessXAxis, seamlessYAxis, shouldUseCpuNoise } = useAppSelector(selector); const { t } = useTranslation(); const activeLabel = useMemo(() => { @@ -34,7 +34,7 @@ export default function ParamAdvancedCollapse() { activeLabel.push(t('parameters.gpuNoise')); } - if (clipSkip > 0) { + if (clipSkip > 0 && model && model.base_model !== 'sdxl') { activeLabel.push( t('parameters.clipSkipWithLayerCount', { layerCount: clipSkip }) ); @@ -49,15 +49,19 @@ export default function ParamAdvancedCollapse() { } return activeLabel.join(', '); - }, [clipSkip, seamlessXAxis, seamlessYAxis, shouldUseCpuNoise, t]); + }, [clipSkip, model, seamlessXAxis, seamlessYAxis, shouldUseCpuNoise, t]); return ( - - + {model && model?.base_model !== 'sdxl' && ( + <> + + + + )} diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamClipSkip.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamClipSkip.tsx index a7d3d3c655..a5ab8b9a94 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamClipSkip.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Advanced/ParamClipSkip.tsx @@ -42,6 +42,10 @@ export default function ParamClipSkip() { return clipSkipMap[model.base_model].markers; }, [model]); + if (model?.base_model === 'sdxl') { + return null; + } + return ( Date: Thu, 21 Sep 2023 14:50:55 +1000 Subject: [PATCH 09/87] feat(ui): enable control adapters on image drop - Dropping/uploading an image on control adapter enables it (controlnet & ip adapter) - The image components are always enabled to allow this --- .../listeners/imageDropped.ts | 9 +++++++ .../listeners/imageUploaded.ts | 9 +++++++ .../controlNet/components/ControlNet.tsx | 22 +++++++++++------ .../components/ControlNetImagePreview.tsx | 8 ++----- .../ipAdapter/ParamIPAdapterFeatureToggle.tsx | 13 ++++++---- .../ipAdapter/ParamIPAdapterImage.tsx | 24 ++++++++++--------- .../ipAdapter/ParamIPAdapterModelSelect.tsx | 4 ++++ .../controlNet/store/controlNetSlice.ts | 16 ++++++------- .../ControlNet/ParamControlNetCollapse.tsx | 7 +++--- 9 files changed, 72 insertions(+), 40 deletions(-) diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDropped.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDropped.ts index e8b4aa9210..d38a20a917 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDropped.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDropped.ts @@ -4,7 +4,9 @@ import { parseify } from 'common/util/serialize'; import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice'; import { controlNetImageChanged, + controlNetIsEnabledChanged, ipAdapterImageChanged, + isIPAdapterEnabledChanged, } from 'features/controlNet/store/controlNetSlice'; import { TypesafeDraggableData, @@ -99,6 +101,12 @@ export const addImageDroppedListener = () => { controlNetId, }) ); + dispatch( + controlNetIsEnabledChanged({ + controlNetId, + isEnabled: true, + }) + ); return; } @@ -111,6 +119,7 @@ export const addImageDroppedListener = () => { activeData.payload.imageDTO ) { dispatch(ipAdapterImageChanged(activeData.payload.imageDTO)); + dispatch(isIPAdapterEnabledChanged(true)); return; } diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts index 1c7caaeb2f..b27c922342 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts @@ -3,7 +3,9 @@ import { logger } from 'app/logging/logger'; import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice'; import { controlNetImageChanged, + controlNetIsEnabledChanged, ipAdapterImageChanged, + isIPAdapterEnabledChanged, } from 'features/controlNet/store/controlNetSlice'; import { fieldImageValueChanged } from 'features/nodes/store/nodesSlice'; import { initialImageChanged } from 'features/parameters/store/generationSlice'; @@ -87,6 +89,12 @@ export const addImageUploadedFulfilledListener = () => { if (postUploadAction?.type === 'SET_CONTROLNET_IMAGE') { const { controlNetId } = postUploadAction; + dispatch( + controlNetIsEnabledChanged({ + controlNetId, + isEnabled: true, + }) + ); dispatch( controlNetImageChanged({ controlNetId, @@ -104,6 +112,7 @@ export const addImageUploadedFulfilledListener = () => { if (postUploadAction?.type === 'SET_IP_ADAPTER_IMAGE') { dispatch(ipAdapterImageChanged(imageDTO)); + dispatch(isIPAdapterEnabledChanged(true)); dispatch( addToast({ ...DEFAULT_UPLOADED_TOAST, diff --git a/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx b/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx index 13ceaf4173..3d00359d18 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx @@ -1,12 +1,12 @@ import { Box, Flex } from '@chakra-ui/react'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { memo, useCallback } from 'react'; +import { ChangeEvent, memo, useCallback } from 'react'; import { FaCopy, FaTrash } from 'react-icons/fa'; import { ControlNetConfig, controlNetDuplicated, controlNetRemoved, - controlNetToggled, + controlNetIsEnabledChanged, } from '../store/controlNetSlice'; import ParamControlNetModel from './parameters/ParamControlNetModel'; import ParamControlNetWeight from './parameters/ParamControlNetWeight'; @@ -77,9 +77,17 @@ const ControlNet = (props: ControlNetProps) => { ); }, [controlNetId, dispatch]); - const handleToggleIsEnabled = useCallback(() => { - dispatch(controlNetToggled({ controlNetId })); - }, [controlNetId, dispatch]); + const handleToggleIsEnabled = useCallback( + (e: ChangeEvent) => { + dispatch( + controlNetIsEnabledChanged({ + controlNetId, + isEnabled: e.target.checked, + }) + ); + }, + [controlNetId, dispatch] + ); return ( { sx={{ w: 'full', minW: 0, - opacity: isEnabled ? 1 : 0.5, - pointerEvents: isEnabled ? 'auto' : 'none', + // opacity: isEnabled ? 1 : 0.5, + // pointerEvents: isEnabled ? 'auto' : 'none', transitionProperty: 'common', transitionDuration: '0.1s', }} diff --git a/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx b/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx index 02c65c1c83..0b1e0dab87 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/ControlNetImagePreview.tsx @@ -13,6 +13,7 @@ import { import { setHeight, setWidth } from 'features/parameters/store/generationSlice'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { memo, useCallback, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { FaRulerVertical, FaSave, FaUndo } from 'react-icons/fa'; import { useAddImageToBoardMutation, @@ -26,7 +27,6 @@ import { ControlNetConfig, controlNetImageChanged, } from '../store/controlNetSlice'; -import { useTranslation } from 'react-i18next'; type Props = { controlNet: ControlNetConfig; @@ -52,7 +52,6 @@ const ControlNetImagePreview = ({ isSmall, controlNet }: Props) => { controlImage: controlImageName, processedControlImage: processedControlImageName, processorType, - isEnabled, controlNetId, } = controlNet; @@ -172,15 +171,13 @@ const ControlNetImagePreview = ({ isSmall, controlNet }: Props) => { h: isSmall ? 28 : 366, // magic no touch alignItems: 'center', justifyContent: 'center', - pointerEvents: isEnabled ? 'auto' : 'none', - opacity: isEnabled ? 1 : 0.5, }} > @@ -202,7 +199,6 @@ const ControlNetImagePreview = ({ isSmall, controlNet }: Props) => { droppableData={droppableData} imageDTO={processedControlImage} isUploadDisabled={true} - isDropDisabled={!isEnabled} /> diff --git a/invokeai/frontend/web/src/features/controlNet/components/ipAdapter/ParamIPAdapterFeatureToggle.tsx b/invokeai/frontend/web/src/features/controlNet/components/ipAdapter/ParamIPAdapterFeatureToggle.tsx index c077e7a824..7fae538cf0 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/ipAdapter/ParamIPAdapterFeatureToggle.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/ipAdapter/ParamIPAdapterFeatureToggle.tsx @@ -3,8 +3,8 @@ import { stateSelector } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import IAISwitch from 'common/components/IAISwitch'; -import { isIPAdapterEnableToggled } from 'features/controlNet/store/controlNetSlice'; -import { memo, useCallback } from 'react'; +import { isIPAdapterEnabledChanged } from 'features/controlNet/store/controlNetSlice'; +import { ChangeEvent, memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; const selector = createSelector( @@ -22,9 +22,12 @@ const ParamIPAdapterFeatureToggle = () => { const dispatch = useAppDispatch(); const { t } = useTranslation(); - const handleChange = useCallback(() => { - dispatch(isIPAdapterEnableToggled()); - }, [dispatch]); + const handleChange = useCallback( + (e: ChangeEvent) => { + dispatch(isIPAdapterEnabledChanged(e.target.checked)); + }, + [dispatch] + ); return ( { + const { ipAdapterInfo } = controlNet; + return { ipAdapterInfo }; + }, + defaultSelectorOptions +); + const ParamIPAdapterImage = () => { - const ipAdapterInfo = useAppSelector( - (state: RootState) => state.controlNet.ipAdapterInfo - ); - - const isIPAdapterEnabled = useAppSelector( - (state: RootState) => state.controlNet.isIPAdapterEnabled - ); - + const { ipAdapterInfo } = useAppSelector(selector); const dispatch = useAppDispatch(); const { t } = useTranslation(); @@ -71,8 +75,6 @@ const ParamIPAdapterImage = () => { droppableData={droppableData} draggableData={draggableData} postUploadAction={postUploadAction} - isUploadDisabled={!isIPAdapterEnabled} - isDropDisabled={!isIPAdapterEnabled} dropLabel={t('toast.setIPAdapterImage')} noContentFallback={ { + const isEnabled = useAppSelector( + (state: RootState) => state.controlNet.isIPAdapterEnabled + ); const ipAdapterModel = useAppSelector( (state: RootState) => state.controlNet.ipAdapterInfo.model ); @@ -90,6 +93,7 @@ const ParamIPAdapterModelSelect = () => { data={data} onChange={handleValueChanged} sx={{ width: '100%' }} + disabled={!isEnabled} /> ); }; diff --git a/invokeai/frontend/web/src/features/controlNet/store/controlNetSlice.ts b/invokeai/frontend/web/src/features/controlNet/store/controlNetSlice.ts index 3fe57f4a84..70c459f0a4 100644 --- a/invokeai/frontend/web/src/features/controlNet/store/controlNetSlice.ts +++ b/invokeai/frontend/web/src/features/controlNet/store/controlNetSlice.ts @@ -146,16 +146,16 @@ export const controlNetSlice = createSlice({ const { controlNetId } = action.payload; delete state.controlNets[controlNetId]; }, - controlNetToggled: ( + controlNetIsEnabledChanged: ( state, - action: PayloadAction<{ controlNetId: string }> + action: PayloadAction<{ controlNetId: string; isEnabled: boolean }> ) => { - const { controlNetId } = action.payload; + const { controlNetId, isEnabled } = action.payload; const cn = state.controlNets[controlNetId]; if (!cn) { return; } - cn.isEnabled = !cn.isEnabled; + cn.isEnabled = isEnabled; }, controlNetImageChanged: ( state, @@ -377,8 +377,8 @@ export const controlNetSlice = createSlice({ controlNetReset: () => { return { ...initialControlNetState }; }, - isIPAdapterEnableToggled: (state) => { - state.isIPAdapterEnabled = !state.isIPAdapterEnabled; + isIPAdapterEnabledChanged: (state, action: PayloadAction) => { + state.isIPAdapterEnabled = action.payload; }, ipAdapterImageChanged: (state, action: PayloadAction) => { state.ipAdapterInfo.adapterImage = action.payload; @@ -450,7 +450,7 @@ export const { controlNetRemoved, controlNetImageChanged, controlNetProcessedImageChanged, - controlNetToggled, + controlNetIsEnabledChanged, controlNetModelChanged, controlNetWeightChanged, controlNetBeginStepPctChanged, @@ -461,7 +461,7 @@ export const { controlNetProcessorTypeChanged, controlNetReset, controlNetAutoConfigToggled, - isIPAdapterEnableToggled, + isIPAdapterEnabledChanged, ipAdapterImageChanged, ipAdapterWeightChanged, ipAdapterModelChanged, diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx index cd276713c3..844bda8b3d 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx @@ -23,17 +23,18 @@ import { v4 as uuidv4 } from 'uuid'; const selector = createSelector( [stateSelector], ({ controlNet }) => { - const { controlNets, isEnabled, isIPAdapterEnabled } = controlNet; + const { controlNets, isEnabled, isIPAdapterEnabled, ipAdapterInfo } = + controlNet; const validControlNets = getValidControlNets(controlNets); - + const isIPAdapterValid = ipAdapterInfo.model && ipAdapterInfo.adapterImage; let activeLabel = undefined; if (isEnabled && validControlNets.length > 0) { activeLabel = `${validControlNets.length} ControlNet`; } - if (isIPAdapterEnabled) { + if (isIPAdapterEnabled && isIPAdapterValid) { if (activeLabel) { activeLabel = `${activeLabel}, IP Adapter`; } else { From 83ce8ef1ec375f5a5b3f5582c5c3355c496fb2a6 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 21 Sep 2023 14:54:47 +1000 Subject: [PATCH 10/87] fix(nodes): clipskip metadata entry is optional --- invokeai/app/invocations/metadata.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/invokeai/app/invocations/metadata.py b/invokeai/app/invocations/metadata.py index 39fa3beba0..a84befcb2e 100644 --- a/invokeai/app/invocations/metadata.py +++ b/invokeai/app/invocations/metadata.py @@ -42,7 +42,8 @@ class CoreMetadata(BaseModelExcludeNull): cfg_scale: float = Field(description="The classifier-free guidance scale parameter") steps: int = Field(description="The number of steps used for inference") scheduler: str = Field(description="The scheduler used for inference") - clip_skip: int = Field( + clip_skip: Optional[int] = Field( + default=None, description="The number of skipped CLIP layers", ) model: MainModelField = Field(description="The main model used for inference") @@ -116,7 +117,8 @@ class MetadataAccumulatorInvocation(BaseInvocation): cfg_scale: float = InputField(description="The classifier-free guidance scale parameter") steps: int = InputField(description="The number of steps used for inference") scheduler: str = InputField(description="The scheduler used for inference") - clip_skip: int = InputField( + clip_skip: Optional[int] = Field( + default=None, description="The number of skipped CLIP layers", ) model: MainModelField = InputField(description="The main model used for inference") From b4790002c76ef3ed045c01b4038ee4d0f8bd4864 Mon Sep 17 00:00:00 2001 From: Wubbbi Date: Thu, 21 Sep 2023 13:45:55 +0200 Subject: [PATCH 11/87] Add python-socketio depencency (mandatory) --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index e9d24b7fa0..c2a9bae494 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,6 +67,7 @@ dependencies = [ 'pyperclip', "pyreadline3", "python-multipart", + "python-socketio", "pytorch-lightning", "realesrgan", "requests~=2.28.2", From 6d1057c5601af27b2a03f7d18da095b90bc0b3ad Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 21 Sep 2023 16:41:35 +1000 Subject: [PATCH 12/87] fix(ui): skip firing collision detection on dnd when droppable scrolled out Requires some additional logic in the collision detection algorithm. Closes #4621 --- .../src/common/components/IAIDroppable.tsx | 2 +- .../features/dnd/components/AppDndContext.tsx | 4 +- .../features/dnd/util/customPointerWithin.ts | 38 +++++++++++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 invokeai/frontend/web/src/features/dnd/util/customPointerWithin.ts diff --git a/invokeai/frontend/web/src/common/components/IAIDroppable.tsx b/invokeai/frontend/web/src/common/components/IAIDroppable.tsx index e4fb121c78..bf98961c21 100644 --- a/invokeai/frontend/web/src/common/components/IAIDroppable.tsx +++ b/invokeai/frontend/web/src/common/components/IAIDroppable.tsx @@ -31,7 +31,7 @@ const IAIDroppable = (props: IAIDroppableProps) => { insetInlineStart={0} w="full" h="full" - pointerEvents="none" + pointerEvents={active ? 'auto' : 'none'} > {isValidDrop(data, active) && ( diff --git a/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx b/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx index bffe738aa9..bd77383843 100644 --- a/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx +++ b/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx @@ -2,7 +2,6 @@ import { DragOverlay, MouseSensor, TouchSensor, - pointerWithin, useSensor, useSensors, } from '@dnd-kit/core'; @@ -14,6 +13,7 @@ import { AnimatePresence, motion } from 'framer-motion'; import { PropsWithChildren, memo, useCallback, useState } from 'react'; import { useScaledModifer } from '../hooks/useScaledCenteredModifer'; import { DragEndEvent, DragStartEvent, TypesafeDraggableData } from '../types'; +import { customPointerWithin } from '../util/customPointerWithin'; import { DndContextTypesafe } from './DndContextTypesafe'; import DragPreview from './DragPreview'; @@ -77,7 +77,7 @@ const AppDndContext = (props: PropsWithChildren) => { onDragStart={handleDragStart} onDragEnd={handleDragEnd} sensors={sensors} - collisionDetection={pointerWithin} + collisionDetection={customPointerWithin} autoScroll={false} > {props.children} diff --git a/invokeai/frontend/web/src/features/dnd/util/customPointerWithin.ts b/invokeai/frontend/web/src/features/dnd/util/customPointerWithin.ts new file mode 100644 index 0000000000..68f1e98b16 --- /dev/null +++ b/invokeai/frontend/web/src/features/dnd/util/customPointerWithin.ts @@ -0,0 +1,38 @@ +import { CollisionDetection, pointerWithin } from '@dnd-kit/core'; + +/** + * Filters out droppable elements that are overflowed, then applies the pointerWithin collision detection. + * + * Fixes collision detection firing on droppables that are not visible, having been scrolled out of view. + * + * See https://github.com/clauderic/dnd-kit/issues/1198 + */ +export const customPointerWithin: CollisionDetection = (arg) => { + if (!arg.pointerCoordinates) { + // sanity check + return []; + } + + // Get all elements at the pointer coordinates. This excludes elements which are overflowed, + // so it won't include the droppable elements that are scrolled out of view. + const targetElements = document.elementsFromPoint( + arg.pointerCoordinates.x, + arg.pointerCoordinates.y + ); + + const filteredDroppableContainers = arg.droppableContainers.filter( + (container) => { + if (!container.node.current) { + return false; + } + // Only include droppable elements that are in the list of elements at the pointer coordinates. + return targetElements.includes(container.node.current); + } + ); + + // Run the provided collision detection with the filtered droppable elements. + return pointerWithin({ + ...arg, + droppableContainers: filteredDroppableContainers, + }); +}; From b6e9cd4fe2d314fc229a49f731ab8104835c1f98 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:21:25 +1000 Subject: [PATCH 13/87] feat(ui): show cursor on drag previews --- .../frontend/web/src/features/dnd/components/AppDndContext.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx b/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx index bd77383843..520abc33ed 100644 --- a/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx +++ b/invokeai/frontend/web/src/features/dnd/components/AppDndContext.tsx @@ -87,7 +87,7 @@ const AppDndContext = (props: PropsWithChildren) => { style={{ width: 'min-content', height: 'min-content', - cursor: 'none', + cursor: 'grabbing', userSelect: 'none', // expand overlay to prevent cursor from going outside it and displaying padding: '10rem', From 5aefa49d7d80ce3cd7e79a1f70cb3c5aec66dd7d Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 21 Sep 2023 20:01:00 +1000 Subject: [PATCH 14/87] fix(ui): popover ref & wrapping of children (wip) --- invokeai/frontend/web/public/locales/en.json | 18 ++-- .../components/IAIInformationalPopover.tsx | 86 +++++++++++-------- .../components/IAIMantineMultiSelect.tsx | 10 ++- .../components/IAIMantineSearchableSelect.tsx | 10 ++- .../common/components/IAIMantineSelect.tsx | 10 ++- .../src/common/components/IAINumberInput.tsx | 8 +- .../web/src/common/components/IAISlider.tsx | 8 +- .../web/src/common/components/IAISwitch.tsx | 2 + .../Parameters/Core/ParamIterations.tsx | 4 +- .../Core/ParamNegativeConditioning.tsx | 47 +++++----- .../Core/ParamPositiveConditioning.tsx | 23 ++--- .../MainModel/ParamMainModelSelect.tsx | 18 ++-- .../web/src/theme/components/popover.ts | 2 +- 13 files changed, 140 insertions(+), 106 deletions(-) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index c309e4de50..f48df3368f 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1213,14 +1213,14 @@ }, "dynamicPromptsCombinatorial": { "heading": "Combinatorial Generation", - "paragraph": "Generate an image for every possible combination of Dynamic Prompt until the Max Prompts is reached." + "paragraph": "Generate an image for every possible combination of Dynamic Prompts until the Max Prompts is reached." }, "infillMethod": { "heading": "Infill Method", "paragraph": "Method to infill the selected area." }, "lora": { - "heading": "LoRA", + "heading": "LoRA Weight", "paragraph": "Weight of the LoRA. Higher weight will lead to larger impacts on the final image." }, "noiseEnable": { @@ -1239,21 +1239,21 @@ "heading": "Denoising Strength", "paragraph": "How much noise is added to the input image. 0 will result in an identical image, while 1 will result in a completely new image." }, - "paramImages": { - "heading": "Images", - "paragraph": "Number of images that will be generated." + "paramIterations": { + "heading": "Iterations", + "paragraph": "The number of images to generate. If Dynamic Prompts is enabled, each of the prompts will be generated this many times." }, "paramModel": { "heading": "Model", "paragraph": "Model used for the denoising steps. Different models are trained to specialize in producing different aesthetic results and content." }, "paramNegativeConditioning": { - "heading": "Negative Prompts", - "paragraph": "This is where you enter your negative prompts." + "heading": "Negative Prompt", + "paragraph": "The generation process avoids the concepts in the negative prompt. Use this to exclude qualities or objects from the output. Supports Compel syntax and embeddings." }, "paramPositiveConditioning": { - "heading": "Positive Prompts", - "paragraph": "This is where you enter your positive prompts." + "heading": "Positive Prompt", + "paragraph": "Guides the generation process. You may use any words or phrases. Supports Compel and Dynamic Prompts syntaxes and embeddings." }, "paramRatio": { "heading": "Ratio", diff --git a/invokeai/frontend/web/src/common/components/IAIInformationalPopover.tsx b/invokeai/frontend/web/src/common/components/IAIInformationalPopover.tsx index 876ce6488a..4a9dd82665 100644 --- a/invokeai/frontend/web/src/common/components/IAIInformationalPopover.tsx +++ b/invokeai/frontend/web/src/common/components/IAIInformationalPopover.tsx @@ -1,37 +1,43 @@ import { + Box, Button, - Popover, - PopoverTrigger, - PopoverContent, - PopoverArrow, - PopoverCloseButton, - PopoverHeader, - PopoverBody, - PopoverProps, + Divider, Flex, - Text, + Heading, Image, + Popover, + PopoverArrow, + PopoverBody, + PopoverCloseButton, + PopoverContent, + PopoverProps, + PopoverTrigger, + Portal, + Text, } from '@chakra-ui/react'; -import { useAppSelector } from '../../app/store/storeHooks'; +import { ReactNode, memo } from 'react'; import { useTranslation } from 'react-i18next'; +import { useAppSelector } from '../../app/store/storeHooks'; -interface Props extends PopoverProps { +const OPEN_DELAY = 1500; + +type Props = Omit & { details: string; - children: JSX.Element; + children: ReactNode; image?: string; buttonLabel?: string; buttonHref?: string; placement?: PopoverProps['placement']; -} +}; -function IAIInformationalPopover({ +const IAIInformationalPopover = ({ details, image, buttonLabel, buttonHref, children, placement, -}: Props): JSX.Element { +}: Props) => { const shouldEnableInformationalPopovers = useAppSelector( (state) => state.system.shouldEnableInformationalPopovers ); @@ -41,18 +47,21 @@ function IAIInformationalPopover({ const paragraph = t(`popovers.${details}.paragraph`); if (!shouldEnableInformationalPopovers) { - return children; - } else { - return ( - - -
{children}
-
+ return <>{children}; + } + + return ( + + + {children} + + @@ -83,14 +92,17 @@ function IAIInformationalPopover({ gap: 3, flexDirection: 'column', width: '100%', - p: 3, - pt: heading ? 0 : 3, }} > - {heading && {heading}} - {paragraph} + {heading && ( + <> + {heading} + + + )} + {paragraph} {buttonLabel && ( - +