Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20f1f16d36 |
@@ -1,21 +0,0 @@
|
||||
name: Publish to Comfy registry
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "pyproject.toml"
|
||||
|
||||
jobs:
|
||||
publish-node:
|
||||
name: Publish Custom Node to registry
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Publish Custom Node
|
||||
uses: Comfy-Org/publish-node-action@main
|
||||
with:
|
||||
## Add your own personal access token to your Github Repository secrets and reference it here.
|
||||
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
|
||||
@@ -2,7 +2,6 @@
|
||||
This repository offers various extension nodes for ComfyUI. Nodes here have different characteristics compared to those in the ComfyUI Impact Pack. The Impact Pack has become too large now...
|
||||
|
||||
## Notice:
|
||||
* V0.73 The Variation Seed feature is added to Regional Prompt nodes, and it is only compatible with versions Impact Pack V5.10 and above.
|
||||
* V0.69 incompatible with the outdated **ComfyUI IPAdapter Plus**. (A version dated March 24th or later is required.)
|
||||
* V0.64 add sigma_factor to RegionalPrompt... nodes required Impact Pack V4.76 or later.
|
||||
* V0.62 support faceid in Regional IPAdapter
|
||||
@@ -11,46 +10,39 @@ This repository offers various extension nodes for ComfyUI. Nodes here have diff
|
||||
* WARN: If you use version **0.12 to 0.12.2** without a GlobalSeed node, your workflow's seed may have been erased. Please update immediately.
|
||||
|
||||
## Nodes
|
||||
### Lora Block Weight - This is a node that provides functionality related to Lora block weight.
|
||||
* This provides similar functionality to [sd-webui-lora-block-weight](https://github.com/hako-mikan/sd-webui-lora-block-weight)
|
||||
* `Lora Loader (Block Weight)`: When loading Lora, the block weight vector is applied.
|
||||
* In the block vector, you can use numbers, R, A, a, B, and b.
|
||||
* R is determined sequentially based on a random seed, while A and B represent the values of the A and B parameters, respectively. a and b are half of the values of A and B, respectively.
|
||||
* `XY Input: Lora Block Weight`: This is a node in the [Efficiency Nodes](https://github.com/LucianoCirino/efficiency-nodes-comfyui)' XY Plot that allows you to use Lora block weight.
|
||||
* You must ensure that X and Y connections are made, and dependencies should be connected to the XY Plot.
|
||||
* Note: To use this feature, update `Efficient Nodes` to a version released after September 3rd.
|
||||
* Lora Block Weight - This is a node that provides functionality related to Lora block weight.
|
||||
* This provides similar functionality to [sd-webui-lora-block-weight](https://github.com/hako-mikan/sd-webui-lora-block-weight)
|
||||
* `Lora Loader (Block Weight)`: When loading Lora, the block weight vector is applied.
|
||||
* In the block vector, you can use numbers, R, A, a, B, and b.
|
||||
* R is determined sequentially based on a random seed, while A and B represent the values of the A and B parameters, respectively. a and b are half of the values of A and B, respectively.
|
||||
* `XY Input: Lora Block Weight`: This is a node in the [Efficiency Nodes](https://github.com/LucianoCirino/efficiency-nodes-comfyui)' XY Plot that allows you to use Lora block weight.
|
||||
* You must ensure that X and Y connections are made, and dependencies should be connected to the XY Plot.
|
||||
* Note: To use this feature, update `Efficient Nodes` to a version released after September 3rd.
|
||||
|
||||
### SEGS Supports nodes - This is a node that supports ApplyControlNet (SEGS) from the Impact Pack.
|
||||
* `OpenPose Preprocessor Provider (SEGS)`: OpenPose preprocessor is applied for the purpose of using OpenPose ControlNet in SEGS.
|
||||
* You need to install [ControlNet Auxiliary Preprocessors](https://github.com/Fannovel16/comfyui_controlnet_aux) to use this.
|
||||
* `Canny Preprocessor Provider (SEGS)`: Canny preprocessor is applied for the purpose of using Canny ControlNet in SEGS.
|
||||
* `DW Preprocessor Provider (SEGS)`, `MiDaS Depth Map Preprocessor Provider (SEGS)`, `LeReS Depth Map Preprocessor Provider (SEGS)`,
|
||||
`MediaPipe FaceMesh Preprocessor Provider (SEGS)`, `HED Preprocessor Provider (SEGS)`, `Fake Scribble Preprocessor (SEGS)`,
|
||||
`AnimeLineArt Preprocessor Provider (SEGS)`, `Manga2Anime LineArt Preprocessor Provider (SEGS)`, `LineArt Preprocessor Provider (SEGS)`,
|
||||
`Color Preprocessor Provider (SEGS)`, `Inpaint Preprocessor Provider (SEGS)`, `Tile Preprocessor Provider (SEGS)`, `MeshGraphormer Depth Map Preprocessor Provider (SEGS)`
|
||||
* `MediaPipeFaceMeshDetectorProvider`: This node provides `BBOX_DETECTOR` and `SEGM_DETECTOR` that can be used in Impact Pack's Detector using the `MediaPipe-FaceMesh Preprocessor` of ControlNet Auxiliary Preprocessors.
|
||||
* SEGS Supports nodes - This is a node that supports ApplyControlNet (SEGS) from the Impact Pack.
|
||||
* `OpenPose Preprocessor Provider (SEGS)`: OpenPose preprocessor is applied for the purpose of using OpenPose ControlNet in SEGS.
|
||||
* You need to install [ControlNet Auxiliary Preprocessors](https://github.com/Fannovel16/comfyui_controlnet_aux) to use this.
|
||||
* `Canny Preprocessor Provider (SEGS)`: Canny preprocessor is applied for the purpose of using Canny ControlNet in SEGS.
|
||||
* `DW Preprocessor Provider (SEGS)`, `MiDaS Depth Map Preprocessor Provider (SEGS)`, `LeReS Depth Map Preprocessor Provider (SEGS)`,
|
||||
`MediaPipe FaceMesh Preprocessor Provider (SEGS)`, `HED Preprocessor Provider (SEGS)`, `Fake Scribble Preprocessor (SEGS)`,
|
||||
`AnimeLineArt Preprocessor Provider (SEGS)`, `Manga2Anime LineArt Preprocessor Provider (SEGS)`, `LineArt Preprocessor Provider (SEGS)`,
|
||||
`Color Preprocessor Provider (SEGS)`, `Inpaint Preprocessor Provider (SEGS)`, `Tile Preprocessor Provider (SEGS)`, `MeshGraphormer Depth Map Preprocessor Provider (SEGS)`
|
||||
* `MediaPipeFaceMeshDetectorProvider`: This node provides `BBOX_DETECTOR` and `SEGM_DETECTOR` that can be used in Impact Pack's Detector using the `MediaPipe-FaceMesh Preprocessor` of ControlNet Auxiliary Preprocessors.
|
||||
|
||||
### A1111 Compatibility support - These nodes assists in replicating the creation of A1111 in ComfyUI exactly.
|
||||
* `KSampler (Inspire)`: ComfyUI uses the CPU for generating random noise, while A1111 uses the GPU. One of the three factors that significantly impact reproducing A1111's results in ComfyUI can be addressed using `KSampler (Inspire)`.
|
||||
* Other point #1 : Please make sure you haven't forgotten to include 'embedding:' in the embedding used in the prompt, like 'embedding:easynegative.'
|
||||
* Other point #2 : ComfyUI and A1111 have different interpretations of weighting. To align them, you need to use [BlenderNeko/Advanced CLIP Text Encode](https://github.com/BlenderNeko/ComfyUI_ADV_CLIP_emb).
|
||||
* `KSamplerAdvanced (Inspire)`: Inspire Pack version of `KSampler (Advanced)`.
|
||||
* `RandomNoise (inspire)`: Inspire Pack version of `RandomNoise`.
|
||||
* Common Parameters
|
||||
* `batch_seed_mode` determines how seeds are applied to batch latents:
|
||||
* `comfy`: This method applies the noise to batch latents all at once. This is advantageous to prevent duplicate images from being generated due to seed duplication when creating images.
|
||||
* `incremental`: Similar to the A1111 case, this method incrementally increases the seed and applies noise sequentially for each batch. This approach is beneficial for straightforward reproduction using only the seed.
|
||||
* `variation_strength`: In each batch, the variation strength starts from the set `variation_strength` and increases by `xxx`.
|
||||
* `variation_seed` and `variation_strength` - Initial noise generated by the seed is transformed to the shape of `variation_seed` by `variation_strength`. If `variation_strength` is 0, it only relies on the influence of the seed, and if `variation_strength` is 1.0, it is solely influenced by `variation_seed`.
|
||||
* These parameters are used when you want to maintain the composition of an image generated by the seed but wish to introduce slight changes.
|
||||
* A1111 Compatibility support - These nodes assists in replicating the creation of A1111 in ComfyUI exactly.
|
||||
* `KSampler (Inspire)`: ComfyUI uses the CPU for generating random noise, while A1111 uses the GPU. One of the three factors that significantly impact reproducing A1111's results in ComfyUI can be addressed using `KSampler (Inspire)`.
|
||||
* Other point #1 : Please make sure you haven't forgotten to include 'embedding:' in the embedding used in the prompt, like 'embedding:easynegative.'
|
||||
* Other point #2 : ComfyUI and A1111 have different interpretations of weighting. To align them, you need to use [BlenderNeko/Advanced CLIP Text Encode](https://github.com/BlenderNeko/ComfyUI_ADV_CLIP_emb).
|
||||
* `KSamplerAdvanced (Inspire)`: Inspire Pack version of `KSampler (Advanced)`.
|
||||
* Common Parameters
|
||||
* `batch_seed_mode` determines how seeds are applied to batch latents:
|
||||
* `comfy`: This method applies the noise to batch latents all at once. This is advantageous to prevent duplicate images from being generated due to seed duplication when creating images.
|
||||
* `incremental`: Similar to the A1111 case, this method incrementally increases the seed and applies noise sequentially for each batch. This approach is beneficial for straightforward reproduction using only the seed.
|
||||
* `variation_strength`: In each batch, the variation strength starts from the set `variation_strength` and increases by `xxx`.
|
||||
* `variation_seed` and `variation_strength` - Initial noise generated by the seed is transformed to the shape of `variation_seed` by `variation_strength`. If `variation_strength` is 0, it only relies on the influence of the seed, and if `variation_strength` is 1.0, it is solely influenced by `variation_seed`.
|
||||
* These parameters are used when you want to maintain the composition of an image generated by the seed but wish to introduce slight changes.
|
||||
|
||||
### Sampler nodes
|
||||
* `KSampler Progress (Inspire)` - In KSampler, the sampling process generates latent batches. By using `Video Combine` node from [ComfyUI-VideoHelperSuite](https://github.com/Kosinkadink/ComfyUI-VideoHelperSuite), you can create a video from the progress.
|
||||
* `Scheduled CFGGuider (Inspire)` - This is a CFGGuider that adjusts the schedule from from_cfg to to_cfg using linear, log, and exp methods.
|
||||
* `Scheduled PerpNeg CFGGuider (Inspire)` - This is a PerpNeg CFGGuider that adjusts the schedule from from_cfg to to_cfg using linear, log, and exp methods.
|
||||
|
||||
|
||||
### Prompt Support - These are nodes for supporting prompt processing.
|
||||
* Prompt Support - These are nodes for supporting prompt processing.
|
||||
* `Load Prompts From Dir (Inspire)`: It sequentially reads prompts files from the specified directory. The output it returns is ZIPPED_PROMPT.
|
||||
* Specify the directories located under `ComfyUI-Inspire-Pack/prompts/`
|
||||
* One prompts file can have multiple prompts separated by `---`.
|
||||
@@ -79,13 +71,12 @@ This repository offers various extension nodes for ComfyUI. Nodes here have diff
|
||||
* In the `seed_prompt`, the first seed is considered the initial seed, and the reflection rate is omitted, always defaulting to 1.0.
|
||||
* Each prompt is separated by a comma, and from the second seed onwards, it should follow the format `seed:strength`.
|
||||
* Pressing the "Add to prompt" button will append `additional_seed:additional_strength` to the prompt.
|
||||
* `Composite Noise (Inspire)`: This node overwrites a specific area on top of the destination noise with the source noise.
|
||||
* `Random Generator for List (Inspire)`: When connecting the list output to the signal input, this node generates random values for all items in the list.
|
||||
* `Make Basic Pipe (Inspire)`: This is a node that creates a BASIC_PIPE using Wildcard Encode. The `Add select to` determines whether the selected item from the `Select to...` combo will be input as positive wildcard text or negative wildcard text.
|
||||
* `Remove ControlNet (Inspire)`, `Remove ControlNet [RegionalPrompts] (Inspire)`: Remove ControlNet from CONDITIONING or REGIONAL_PROMPTS.
|
||||
* `Remove ControlNet [RegionalPrompts] (Inspire)` requires Impact Pack V4.73.1 or above.
|
||||
|
||||
### Regional Nodes - These node simplifies the application of prompts by region.
|
||||
* Regional Nodes - These node simplifies the application of prompts by region.
|
||||
* Regional Sampler - These nodes assists in the easy utilization of the regional sampler in the `Impact Pack`.
|
||||
* `Regional Prompt Simple (Inspire)`: This node takes `mask` and `basic_pipe` as inputs and simplifies the creation of `REGIONAL_PROMPTS`.
|
||||
* `Regional Prompt By Color Mask (Inspire)`: Similar to `Regional Prompt Simple (Inspire)`, this function accepts a color mask image as input and defines the region using the color value that will be used as the mask, instead of directly receiving the mask.
|
||||
@@ -100,18 +91,8 @@ This repository offers various extension nodes for ComfyUI. Nodes here have diff
|
||||
* Regional Seed Explorer - These nodes restrict the variation through a seed prompt, applying it only to the masked areas.
|
||||
* `Regional Seed Explorer By Mask (Inspire)`
|
||||
* `Regional Seed Explorer By Color Mask (Inspire)`
|
||||
* `Regional CFG (Inspire)` - By applying a mask as a multiplier to the configured cfg, it allows different areas to have different cfg settings.
|
||||
* `Color Mask To Depth Mask (Inspire)` - Convert the color map from the spec text into a mask with depth values ranging from 0.0 to 1.0.
|
||||
* The range of the mask value is limited to 0.0 to 1.0.
|
||||
* base_value: Sets the value of the base mask.
|
||||
* dilation: Dilation applied to each mask layer before flattening.
|
||||
* flatten_method: The method of flattening the mask layers.
|
||||
* The layers are flattened including the base layer set by base_value.
|
||||
* override: Each pixel is overwritten by the non-zero value of the upper layer.
|
||||
* sum: Each pixel is flattened by summing the values of all layers.
|
||||
* max: Each pixel is flattened by taking the maximum value from all layers.
|
||||
|
||||
### Image Util
|
||||
* Image Util
|
||||
* `Load Image Batch From Dir (Inspire)`: This is almost same as `LoadImagesFromDirectory` of [ComfyUI-Advanced-Controlnet](https://github.com/Kosinkadink/ComfyUI-Advanced-ControlNet). This is just a modified version. Just note that this node forcibly normalizes the size of the loaded image to match the size of the first image, even if they are not the same size, to create a batch image.
|
||||
* `Load Image List From Dir (Inspire)`: This is almost same as `Load Image Batch From Dir (Inspire)`. However, note that this node loads data in a list format, not as a batch, so it returns images at their original size without normalizing the size.
|
||||
* `Load Image (Inspire)`: This node is similar to LoadImage, but the loaded image information is stored in the workflow. The image itself is stored in the workflow, making it easier to reproduce image generation on other computers.
|
||||
@@ -121,8 +102,10 @@ This repository offers various extension nodes for ComfyUI. Nodes here have diff
|
||||
* `ImageBatchSplitter //Inspire`, `LatentBatchSplitter //Inspire`: The script divides a batch of images/latents into individual images/latents, each with a quantity equal to the specified `split_count`. An additional output slot is added for each `split_count`. If the number of images/latents exceeds the `split_count`, the remaining ones are returned as the "remained" output.
|
||||
* `Color Map To Masks (Inspire)`: From the color_map, it extracts the top max_count number of colors and creates masks. min_pixels represents the minimum number of pixels for each color.
|
||||
* `Select Nth Mask (Inspire)`: Extracts the nth mask from the mask batch.
|
||||
|
||||
* KSampler Progress - In KSampler, the sampling process generates latent batches. By using `Video Combine` node from [ComfyUI-VideoHelperSuite](https://github.com/Kosinkadink/ComfyUI-VideoHelperSuite), you can create a video from the progress.
|
||||
|
||||
### Backend Cache - Nodes for storing arbitrary data from the backend in a cache and sharing it across multiple workflows.
|
||||
* Backend Cache - Nodes for storing arbitrary data from the backend in a cache and sharing it across multiple workflows.
|
||||
* `Cache Backend Data (Inspire)`: Stores any backend data in the cache using a string key. Tags are for quick reference.
|
||||
* `Retrieve Backend Data (Inspire)`: Retrieves cached backend data using a string key.
|
||||
* `Remove Backend Data (Inspire)`: Removes cached backend data.
|
||||
@@ -139,20 +122,18 @@ This repository offers various extension nodes for ComfyUI. Nodes here have diff
|
||||
* This node resolves the issue of reloading checkpoints during workflow switching.
|
||||
* `Stable Cascade Checkpoint Loader (Inspire)`: This node provides a feature that allows you to load the `stage_b` and `stage_c` checkpoints of Stable Cascade at once, and it also provides a backend caching feature, optionally.
|
||||
|
||||
### Conditioning - Nodes for conditionings
|
||||
* Conditioning - Nodes for conditionings
|
||||
* `Concat Conditionings with Multiplier (Inspire)`: Concatenating an arbitrary number of Conditionings while applying a multiplier for each Conditioning. The multiplier depends on `comfy_PoP`, so [comfy_PoP](https://github.com/picturesonpictures/comfy_PoP) must be installed.
|
||||
* `Conditioning Upscale (Inspire)`: When upscaling an image, it helps to expand the conditioning area according to the upscale factor. Taken from [ComfyUI_Dave_CustomNode](https://github.com/Davemane42/ComfyUI_Dave_CustomNode)
|
||||
* `Conditioning Stretch (Inspire)`: When upscaling an image, it helps to expand the conditioning area by specifying the original resolution and the new resolution to be applied. Taken from [ComfyUI_Dave_CustomNode](https://github.com/Davemane42/ComfyUI_Dave_CustomNode)
|
||||
|
||||
### Models - Nodes for models
|
||||
* Models - Nodes for models
|
||||
* `IPAdapter Model Helper (Inspire)`: This provides presets that allow for easy loading of the IPAdapter related models. However, it is essential for the model's name to be accurate.
|
||||
* You can download the appropriate model through ComfyUI-Manager.
|
||||
|
||||
### Util - Utilities
|
||||
* Util - Utilities
|
||||
* `Float Range (Inspire)`: Create a float list that increases the value by `step` from `start` to `stop`. A list as large as the maximum limit is created, and when `ensure_end` is enabled, the last value of the list becomes the stop value.
|
||||
* `ToIPAdapterPipe (Inspire)`, `FromIPAdapterPipe (Inspire)`: These nodes assists in conveniently using the bundled ipadapter_model, clip_vision, and model required for applying IPAdapter.
|
||||
* `List Counter (Inspire)`: When each item in the list traverses through this node, it increments a counter by one, generating an integer value.
|
||||
* `RGB Hex To HSV (Inspire)`: Convert an RGB hex string like `#FFD500` to HSV:
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
@@ -168,8 +149,4 @@ Kosinkadink/[ComfyUI-Advanced-Controlnet](https://github.com/Kosinkadink/ComfyUI
|
||||
|
||||
Trung0246/[ComfyUI-0246](https://github.com/Trung0246/ComfyUI-0246) - Nice bypass hack!
|
||||
|
||||
cubiq/[ComfyUI_IPAdapter_plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) - IPAdapter related nodes depend on this extension.
|
||||
|
||||
Davemane42/[ComfyUI_Dave_CustomNode](https://github.com/Davemane42/ComfyUI_Dave_CustomNode) - Original author of ConditioningStretch, ConditioningUpscale
|
||||
|
||||
BlenderNeko/[ComfyUI_Noise](https://github.com/BlenderNeko/ComfyUI_Noise) - slerp code for noise variation
|
||||
cubiq/[ComfyUI_IPAdapter_plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) - IPAdapter related nodes depend on this extension.
|
||||
+2
-3
@@ -7,7 +7,7 @@
|
||||
|
||||
import importlib
|
||||
|
||||
version_code = [0, 82, 4]
|
||||
version_code = [0, 69, 2]
|
||||
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
|
||||
print(f"### Loading: ComfyUI-Inspire-Pack ({version_str})")
|
||||
|
||||
@@ -23,8 +23,7 @@ node_list = [
|
||||
"backend_support",
|
||||
"list_nodes",
|
||||
"conditioning_nodes",
|
||||
"model_nodes",
|
||||
"util_nodes"
|
||||
"model_nodes"
|
||||
]
|
||||
|
||||
NODE_CLASS_MAPPINGS = {}
|
||||
|
||||
+15
-100
@@ -7,61 +7,12 @@ import math
|
||||
from .libs import common
|
||||
|
||||
|
||||
class Inspire_RandomNoise:
|
||||
def __init__(self, seed, mode, incremental_seed_mode, variation_seed, variation_strength, variation_method="linear"):
|
||||
device = comfy.model_management.get_torch_device()
|
||||
self.seed = seed
|
||||
self.noise_device = "cpu" if mode == "CPU" else device
|
||||
self.incremental_seed_mode = incremental_seed_mode
|
||||
self.variation_seed = variation_seed
|
||||
self.variation_strength = variation_strength
|
||||
self.variation_method = variation_method
|
||||
|
||||
def generate_noise(self, input_latent):
|
||||
latent_image = input_latent["samples"]
|
||||
batch_inds = input_latent["batch_index"] if "batch_index" in input_latent else None
|
||||
noise = utils.prepare_noise(latent_image, self.seed, batch_inds, self.noise_device, self.incremental_seed_mode,
|
||||
variation_seed=self.variation_seed, variation_strength=self.variation_strength, variation_method=self.variation_method)
|
||||
return noise.cpu()
|
||||
|
||||
|
||||
class RandomNoise:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"noise_seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||
"noise_mode": (["GPU(=A1111)", "CPU"],),
|
||||
"batch_seed_mode": (["incremental", "comfy", "variation str inc:0.01", "variation str inc:0.05"],),
|
||||
"variation_seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||
"variation_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
},
|
||||
"optional":
|
||||
{"variation_method": (["linear", "slerp"],), }
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("NOISE",)
|
||||
FUNCTION = "get_noise"
|
||||
CATEGORY = "InspirePack/a1111_compat"
|
||||
|
||||
def get_noise(self, noise_seed, noise_mode, batch_seed_mode, variation_seed, variation_strength, variation_method="linear"):
|
||||
return (Inspire_RandomNoise(noise_seed, noise_mode, batch_seed_mode, variation_seed, variation_strength, variation_method=variation_method),)
|
||||
|
||||
|
||||
def inspire_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent, denoise=1.0,
|
||||
noise_mode="CPU", disable_noise=False, start_step=None, last_step=None, force_full_denoise=False,
|
||||
incremental_seed_mode="comfy", variation_seed=None, variation_strength=None, noise=None, callback=None, variation_method="linear",
|
||||
scheduler_func=None):
|
||||
incremental_seed_mode="comfy", variation_seed=None, variation_strength=None, noise=None, callback=None):
|
||||
device = comfy.model_management.get_torch_device()
|
||||
noise_device = "cpu" if noise_mode == "CPU" else device
|
||||
latent_image = latent["samples"]
|
||||
if hasattr(comfy.sample, 'fix_empty_latent_channels'):
|
||||
latent_image = comfy.sample.fix_empty_latent_channels(model, latent_image)
|
||||
|
||||
latent = latent.copy()
|
||||
|
||||
if noise is not None and latent_image.shape[1] != noise.shape[1]:
|
||||
print("[Inspire Pack] inspire_ksampler: The type of latent input for noise generation does not match the model's latent type. When using the SD3 model, you must use the SD3 Empty Latent.")
|
||||
raise Exception("The type of latent input for noise generation does not match the model's latent type. When using the SD3 model, you must use the SD3 Empty Latent.")
|
||||
|
||||
if noise is None:
|
||||
if disable_noise:
|
||||
@@ -69,8 +20,7 @@ def inspire_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive,
|
||||
noise = torch.zeros(latent_image.size(), dtype=latent_image.dtype, layout=latent_image.layout, device=noise_device)
|
||||
else:
|
||||
batch_inds = latent["batch_index"] if "batch_index" in latent else None
|
||||
noise = utils.prepare_noise(latent_image, seed, batch_inds, noise_device, incremental_seed_mode,
|
||||
variation_seed=variation_seed, variation_strength=variation_strength, variation_method=variation_method)
|
||||
noise = utils.prepare_noise(latent_image, seed, batch_inds, noise_device, incremental_seed_mode, variation_seed=variation_seed, variation_strength=variation_strength)
|
||||
|
||||
if start_step is None:
|
||||
if denoise == 1.0:
|
||||
@@ -80,21 +30,9 @@ def inspire_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive,
|
||||
start_step = advanced_steps - steps
|
||||
steps = advanced_steps
|
||||
|
||||
try:
|
||||
samples = common.impact_sampling(
|
||||
model=model, add_noise=not disable_noise, seed=seed, steps=steps, cfg=cfg, sampler_name=sampler_name, scheduler=scheduler, positive=positive, negative=negative,
|
||||
latent_image=latent, start_at_step=start_step, end_at_step=last_step, return_with_leftover_noise=not force_full_denoise, noise=noise, callback=callback,
|
||||
scheduler_func=scheduler_func)
|
||||
except Exception as e:
|
||||
if "unexpected keyword argument 'scheduler_func'" in str(e):
|
||||
print(f"[Inspire Pack] Impact Pack is outdated. (Cannot use GITS scheduler.)")
|
||||
|
||||
samples = common.impact_sampling(
|
||||
model=model, add_noise=not disable_noise, seed=seed, steps=steps, cfg=cfg, sampler_name=sampler_name, scheduler=scheduler, positive=positive, negative=negative,
|
||||
latent_image=latent, start_at_step=start_step, end_at_step=last_step, return_with_leftover_noise=not force_full_denoise, noise=noise, callback=callback)
|
||||
else:
|
||||
raise e
|
||||
|
||||
samples = common.impact_sampling(
|
||||
model=model, add_noise=not disable_noise, seed=seed, steps=steps, cfg=cfg, sampler_name=sampler_name, scheduler=scheduler, positive=positive, negative=negative,
|
||||
latent_image=latent, start_at_step=start_step, end_at_step=last_step, return_with_leftover_noise=not force_full_denoise, noise=noise, callback=callback)
|
||||
return samples, noise
|
||||
|
||||
|
||||
@@ -116,12 +54,7 @@ class KSampler_inspire:
|
||||
"batch_seed_mode": (["incremental", "comfy", "variation str inc:0.01", "variation str inc:0.05"],),
|
||||
"variation_seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||
"variation_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
},
|
||||
"optional":
|
||||
{
|
||||
"variation_method": (["linear", "slerp"],),
|
||||
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("LATENT",)
|
||||
@@ -129,12 +62,8 @@ class KSampler_inspire:
|
||||
|
||||
CATEGORY = "InspirePack/a1111_compat"
|
||||
|
||||
@staticmethod
|
||||
def doit(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise, noise_mode,
|
||||
batch_seed_mode="comfy", variation_seed=None, variation_strength=None, variation_method="linear", scheduler_func_opt=None):
|
||||
return (inspire_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise, noise_mode,
|
||||
incremental_seed_mode=batch_seed_mode, variation_seed=variation_seed, variation_strength=variation_strength, variation_method=variation_method,
|
||||
scheduler_func=scheduler_func_opt)[0], )
|
||||
def doit(self, model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise, noise_mode, batch_seed_mode="comfy", variation_seed=None, variation_strength=None):
|
||||
return (inspire_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise, noise_mode, incremental_seed_mode=batch_seed_mode, variation_seed=variation_seed, variation_strength=variation_strength)[0],)
|
||||
|
||||
|
||||
class KSamplerAdvanced_inspire:
|
||||
@@ -161,9 +90,7 @@ class KSamplerAdvanced_inspire:
|
||||
},
|
||||
"optional":
|
||||
{
|
||||
"variation_method": (["linear", "slerp"],),
|
||||
"noise_opt": ("NOISE",),
|
||||
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,8 +100,7 @@ class KSamplerAdvanced_inspire:
|
||||
CATEGORY = "InspirePack/a1111_compat"
|
||||
|
||||
@staticmethod
|
||||
def sample(model, add_noise, noise_seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step, noise_mode, return_with_leftover_noise,
|
||||
denoise=1.0, batch_seed_mode="comfy", variation_seed=None, variation_strength=None, noise_opt=None, callback=None, variation_method="linear", scheduler_func_opt=None):
|
||||
def sample(model, add_noise, noise_seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step, noise_mode, return_with_leftover_noise, denoise=1.0, batch_seed_mode="comfy", variation_seed=None, variation_strength=None, noise_opt=None, callback=None):
|
||||
force_full_denoise = True
|
||||
|
||||
if return_with_leftover_noise:
|
||||
@@ -188,8 +114,7 @@ class KSamplerAdvanced_inspire:
|
||||
return inspire_ksampler(model, noise_seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image,
|
||||
denoise=denoise, disable_noise=disable_noise, start_step=start_at_step, last_step=end_at_step,
|
||||
force_full_denoise=force_full_denoise, noise_mode=noise_mode, incremental_seed_mode=batch_seed_mode,
|
||||
variation_seed=variation_seed, variation_strength=variation_strength, noise=noise_opt, callback=callback, variation_method=variation_method,
|
||||
scheduler_func=scheduler_func_opt)
|
||||
variation_seed=variation_seed, variation_strength=variation_strength, noise=noise_opt, callback=callback)
|
||||
|
||||
def doit(self, *args, **kwargs):
|
||||
return (self.sample(*args, **kwargs)[0],)
|
||||
@@ -211,11 +136,7 @@ class KSampler_inspire_pipe:
|
||||
"batch_seed_mode": (["incremental", "comfy", "variation str inc:0.01", "variation str inc:0.05"],),
|
||||
"variation_seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||
"variation_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
},
|
||||
"optional":
|
||||
{
|
||||
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("LATENT", "VAE")
|
||||
@@ -223,11 +144,9 @@ class KSampler_inspire_pipe:
|
||||
|
||||
CATEGORY = "InspirePack/a1111_compat"
|
||||
|
||||
def sample(self, basic_pipe, seed, steps, cfg, sampler_name, scheduler, latent_image, denoise, noise_mode, batch_seed_mode="comfy",
|
||||
variation_seed=None, variation_strength=None, scheduler_func_opt=None):
|
||||
def sample(self, basic_pipe, seed, steps, cfg, sampler_name, scheduler, latent_image, denoise, noise_mode, batch_seed_mode="comfy", variation_seed=None, variation_strength=None):
|
||||
model, clip, vae, positive, negative = basic_pipe
|
||||
latent = inspire_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise, noise_mode, incremental_seed_mode=batch_seed_mode,
|
||||
variation_seed=variation_seed, variation_strength=variation_strength, scheduler_func=scheduler_func_opt)[0]
|
||||
latent = inspire_ksampler(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise, noise_mode, incremental_seed_mode=batch_seed_mode, variation_seed=variation_seed, variation_strength=variation_strength)[0]
|
||||
return latent, vae
|
||||
|
||||
|
||||
@@ -254,7 +173,6 @@ class KSamplerAdvanced_inspire_pipe:
|
||||
"optional":
|
||||
{
|
||||
"noise_opt": ("NOISE",),
|
||||
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,8 +181,7 @@ class KSamplerAdvanced_inspire_pipe:
|
||||
|
||||
CATEGORY = "InspirePack/a1111_compat"
|
||||
|
||||
def sample(self, basic_pipe, add_noise, noise_seed, steps, cfg, sampler_name, scheduler, latent_image, start_at_step, end_at_step, noise_mode, return_with_leftover_noise,
|
||||
denoise=1.0, batch_seed_mode="comfy", variation_seed=None, variation_strength=None, noise_opt=None, scheduler_func_opt=None):
|
||||
def sample(self, basic_pipe, add_noise, noise_seed, steps, cfg, sampler_name, scheduler, latent_image, start_at_step, end_at_step, noise_mode, return_with_leftover_noise, denoise=1.0, batch_seed_mode="comfy", variation_seed=None, variation_strength=None, noise_opt=None):
|
||||
model, clip, vae, positive, negative = basic_pipe
|
||||
latent = KSamplerAdvanced_inspire().sample(model=model, add_noise=add_noise, noise_seed=noise_seed,
|
||||
steps=steps, cfg=cfg, sampler_name=sampler_name, scheduler=scheduler,
|
||||
@@ -272,7 +189,7 @@ class KSamplerAdvanced_inspire_pipe:
|
||||
start_at_step=start_at_step, end_at_step=end_at_step,
|
||||
noise_mode=noise_mode, return_with_leftover_noise=return_with_leftover_noise,
|
||||
denoise=denoise, batch_seed_mode=batch_seed_mode, variation_seed=variation_seed,
|
||||
variation_strength=variation_strength, noise_opt=noise_opt, scheduler_func_opt=scheduler_func_opt)[0]
|
||||
variation_strength=variation_strength, noise_opt=noise_opt)[0]
|
||||
return latent, vae
|
||||
|
||||
|
||||
@@ -421,7 +338,6 @@ NODE_CLASS_MAPPINGS = {
|
||||
"KSamplerAdvanced //Inspire": KSamplerAdvanced_inspire,
|
||||
"KSamplerPipe //Inspire": KSampler_inspire_pipe,
|
||||
"KSamplerAdvancedPipe //Inspire": KSamplerAdvanced_inspire_pipe,
|
||||
"RandomNoise //Inspire": RandomNoise,
|
||||
"HyperTile //Inspire": HyperTileInspire
|
||||
}
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
@@ -429,6 +345,5 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"KSamplerAdvanced //Inspire": "KSamplerAdvanced (inspire)",
|
||||
"KSamplerPipe //Inspire": "KSampler [pipe] (inspire)",
|
||||
"KSamplerAdvancedPipe //Inspire": "KSamplerAdvanced [pipe] (inspire)",
|
||||
"RandomNoise //Inspire": "RandomNoise (inspire)",
|
||||
"HyperTile //Inspire": "HyperTile (Inspire)"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import torch
|
||||
import nodes
|
||||
import inspect
|
||||
from .libs import utils
|
||||
from nodes import MAX_RESOLUTION
|
||||
|
||||
|
||||
class ConcatConditioningsWithMultiplier:
|
||||
@@ -19,9 +18,9 @@ class ConcatConditioningsWithMultiplier:
|
||||
flex_inputs["multiplier1"] = ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01})
|
||||
|
||||
return {
|
||||
"required": {"conditioning1": ("CONDITIONING",), },
|
||||
"optional": flex_inputs
|
||||
}
|
||||
"required": {"conditioning1": ("CONDITIONING",), },
|
||||
"optional": flex_inputs
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("CONDITIONING",)
|
||||
FUNCTION = "doit"
|
||||
@@ -48,7 +47,7 @@ class ConcatConditioningsWithMultiplier:
|
||||
if len(conditioning_from) > 1:
|
||||
print(f"Warning: ConcatConditioningsWithMultiplier {k} contains more than 1 cond, only the first one will actually be applied to conditioning1.")
|
||||
|
||||
mkey = 'multiplier' + k[12:]
|
||||
mkey = 'multiplier'+k[12:]
|
||||
multiplier = float(kwargs[mkey])
|
||||
conditioning_from = obj.multiply_conditioning_strength(conditioning=conditioning_from, multiplier=multiplier)[0]
|
||||
cond_from = conditioning_from[0][0]
|
||||
@@ -62,98 +61,16 @@ class ConcatConditioningsWithMultiplier:
|
||||
conditioning_to = out
|
||||
|
||||
if out is None:
|
||||
return (kwargs['conditioning1'],)
|
||||
return (kwargs['conditioning1'], )
|
||||
else:
|
||||
return (out,)
|
||||
|
||||
|
||||
# CREDIT for ConditioningStretch, ConditioningUpscale: Davemane42
|
||||
# Imported to support archived custom nodes.
|
||||
# original code: https://github.com/Davemane42/ComfyUI_Dave_CustomNode/blob/main/MultiAreaConditioning.py
|
||||
class ConditioningStretch:
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"conditioning": ("CONDITIONING",),
|
||||
"resolutionX": ("INT", {"default": 512, "min": 64, "max": MAX_RESOLUTION, "step": 64}),
|
||||
"resolutionY": ("INT", {"default": 512, "min": 64, "max": MAX_RESOLUTION, "step": 64}),
|
||||
"newWidth": ("INT", {"default": 512, "min": 64, "max": MAX_RESOLUTION, "step": 64}),
|
||||
"newHeight": ("INT", {"default": 512, "min": 64, "max": MAX_RESOLUTION, "step": 64}),
|
||||
# "scalar": ("INT", {"default": 2, "min": 1, "max": 100, "step": 0.5}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("CONDITIONING",)
|
||||
CATEGORY = "InspirePack/conditioning"
|
||||
|
||||
FUNCTION = 'upscale'
|
||||
|
||||
@staticmethod
|
||||
def upscale(conditioning, resolutionX, resolutionY, newWidth, newHeight, scalar=1):
|
||||
c = []
|
||||
for t in conditioning:
|
||||
|
||||
n = [t[0], t[1].copy()]
|
||||
if 'area' in n[1]:
|
||||
newWidth *= scalar
|
||||
newHeight *= scalar
|
||||
|
||||
x = ((n[1]['area'][3] * 8) * newWidth / resolutionX) // 8
|
||||
y = ((n[1]['area'][2] * 8) * newHeight / resolutionY) // 8
|
||||
w = ((n[1]['area'][1] * 8) * newWidth / resolutionX) // 8
|
||||
h = ((n[1]['area'][0] * 8) * newHeight / resolutionY) // 8
|
||||
|
||||
n[1]['area'] = tuple(map(lambda x: (((int(x) + 7) >> 3) << 3), [h, w, y, x]))
|
||||
|
||||
c.append(n)
|
||||
|
||||
return (c,)
|
||||
|
||||
|
||||
class ConditioningUpscale:
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"conditioning": ("CONDITIONING",),
|
||||
"scalar": ("INT", {"default": 2, "min": 1, "max": 100, "step": 0.5}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("CONDITIONING",)
|
||||
CATEGORY = "InspirePack/conditioning"
|
||||
|
||||
FUNCTION = 'upscale'
|
||||
|
||||
@staticmethod
|
||||
def upscale(conditioning, scalar):
|
||||
c = []
|
||||
for t in conditioning:
|
||||
|
||||
n = [t[0], t[1].copy()]
|
||||
if 'area' in n[1]:
|
||||
n[1]['area'] = tuple(map(lambda x: ((x * scalar + 7) >> 3) << 3, n[1]['area']))
|
||||
|
||||
c.append(n)
|
||||
|
||||
return (c,)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"ConcatConditioningsWithMultiplier //Inspire": ConcatConditioningsWithMultiplier,
|
||||
"ConditioningUpscale //Inspire": ConditioningUpscale,
|
||||
"ConditioningStretch //Inspire": ConditioningStretch,
|
||||
}
|
||||
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"ConcatConditioningsWithMultiplier //Inspire": "Concat Conditionings with Multiplier (Inspire)",
|
||||
"ConditioningUpscale //Inspire": "Conditioning Upscale (Inspire)",
|
||||
"ConditioningStretch //Inspire": "Conditioning Stretch (Inspire)",
|
||||
}
|
||||
|
||||
@@ -331,17 +331,15 @@ def populate_wildcards(json_data):
|
||||
mbp_updated_widget_values[k] = inputs['positive_populated_text'], inputs['negative_populated_text']
|
||||
|
||||
if 'extra_data' in json_data and 'extra_pnginfo' in json_data['extra_data']:
|
||||
extra_pnginfo = json_data['extra_data']['extra_pnginfo']
|
||||
if 'workflow' in extra_pnginfo and 'nodes' in extra_pnginfo['workflow']:
|
||||
for node in extra_pnginfo['workflow']['nodes']:
|
||||
key = str(node['id'])
|
||||
if key in updated_widget_values:
|
||||
node['widgets_values'][3] = updated_widget_values[key]
|
||||
node['widgets_values'][4] = False
|
||||
if key in mbp_updated_widget_values:
|
||||
node['widgets_values'][7] = mbp_updated_widget_values[key][0]
|
||||
node['widgets_values'][8] = mbp_updated_widget_values[key][1]
|
||||
node['widgets_values'][5] = False
|
||||
for node in json_data['extra_data']['extra_pnginfo']['workflow']['nodes']:
|
||||
key = str(node['id'])
|
||||
if key in updated_widget_values:
|
||||
node['widgets_values'][3] = updated_widget_values[key]
|
||||
node['widgets_values'][4] = False
|
||||
if key in mbp_updated_widget_values:
|
||||
node['widgets_values'][7] = mbp_updated_widget_values[key][0]
|
||||
node['widgets_values'][8] = mbp_updated_widget_values[key][1]
|
||||
node['widgets_values'][5] = False
|
||||
|
||||
|
||||
def force_reset_useless_params(json_data):
|
||||
|
||||
@@ -2,7 +2,7 @@ import comfy
|
||||
import nodes
|
||||
from . import utils
|
||||
|
||||
SCHEDULERS = comfy.samplers.KSampler.SCHEDULERS + ['AYS SDXL', 'AYS SD1', 'AYS SVD', "GITS[coeff=1.2]"]
|
||||
SCHEDULERS = comfy.samplers.KSampler.SCHEDULERS + ['AYS SDXL', 'AYS SD1', 'AYS SVD']
|
||||
|
||||
|
||||
def impact_sampling(*args, **kwargs):
|
||||
|
||||
+8
-87
@@ -4,10 +4,9 @@ import numpy as np
|
||||
import torch
|
||||
from PIL import Image, ImageDraw
|
||||
import math
|
||||
import cv2
|
||||
|
||||
|
||||
def apply_variation_noise(latent_image, noise_device, variation_seed, variation_strength, mask=None, variation_method='linear'):
|
||||
def apply_variation_noise(latent_image, noise_device, variation_seed, variation_strength, mask=None):
|
||||
latent_size = latent_image.size()
|
||||
latent_size_1batch = [1, latent_size[1], latent_size[2], latent_size[3]]
|
||||
|
||||
@@ -28,48 +27,12 @@ def apply_variation_noise(latent_image, noise_device, variation_seed, variation_
|
||||
result = (1 - variation_strength) * latent_image + variation_strength * variation_noise
|
||||
else:
|
||||
# this seems precision is not enough when variation_strength is 0.0
|
||||
mixed_noise = mix_noise(latent_image, variation_noise, variation_strength, variation_method=variation_method)
|
||||
result = (mask == 1).float() * mixed_noise + (mask == 0).float() * latent_image
|
||||
result = (mask == 1).float() * ((1 - variation_strength) * latent_image + variation_strength * variation_noise * mask) + (mask == 0).float() * latent_image
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# CREDIT: https://github.com/BlenderNeko/ComfyUI_Noise/blob/afb14757216257b12268c91845eac248727a55e2/nodes.py#L68
|
||||
# https://discuss.pytorch.org/t/help-regarding-slerp-function-for-generative-model-sampling/32475/3
|
||||
def slerp(val, low, high):
|
||||
dims = low.shape
|
||||
|
||||
low = low.reshape(dims[0], -1)
|
||||
high = high.reshape(dims[0], -1)
|
||||
|
||||
low_norm = low/torch.norm(low, dim=1, keepdim=True)
|
||||
high_norm = high/torch.norm(high, dim=1, keepdim=True)
|
||||
|
||||
low_norm[low_norm != low_norm] = 0.0
|
||||
high_norm[high_norm != high_norm] = 0.0
|
||||
|
||||
omega = torch.acos((low_norm*high_norm).sum(1))
|
||||
so = torch.sin(omega)
|
||||
res = (torch.sin((1.0-val)*omega)/so).unsqueeze(1)*low + (torch.sin(val*omega)/so).unsqueeze(1) * high
|
||||
|
||||
return res.reshape(dims)
|
||||
|
||||
|
||||
def mix_noise(from_noise, to_noise, strength, variation_method):
|
||||
if variation_method == 'slerp':
|
||||
mixed_noise = slerp(strength, from_noise, to_noise)
|
||||
else:
|
||||
# linear
|
||||
mixed_noise = (1 - strength) * from_noise + strength * to_noise
|
||||
|
||||
# NOTE: Since the variance of the Gaussian noise in mixed_noise has changed, it must be corrected through scaling.
|
||||
scale_factor = math.sqrt((1 - strength) ** 2 + strength ** 2)
|
||||
mixed_noise /= scale_factor
|
||||
|
||||
return mixed_noise
|
||||
|
||||
|
||||
def prepare_noise(latent_image, seed, noise_inds=None, noise_device="cpu", incremental_seed_mode="comfy", variation_seed=None, variation_strength=None, variation_method="linear"):
|
||||
def prepare_noise(latent_image, seed, noise_inds=None, noise_device="cpu", incremental_seed_mode="comfy", variation_seed=None, variation_strength=None):
|
||||
"""
|
||||
creates random noise given a latent image and a seed.
|
||||
optional arg skip can be used to skip and discard x number of noise generations for a given seed
|
||||
@@ -100,10 +63,13 @@ def prepare_noise(latent_image, seed, noise_inds=None, noise_device="cpu", incre
|
||||
strength += strength_up
|
||||
|
||||
variation_noise = variation_latent.expand(input_latent.size()[0], -1, -1, -1)
|
||||
mixed_noise = (1 - strength) * input_latent + strength * variation_noise
|
||||
|
||||
mixed_noise = mix_noise(input_latent, variation_noise, strength, variation_method)
|
||||
# NOTE: Since the variance of the Gaussian noise in mixed_noise has changed, it must be corrected through scaling.
|
||||
scale_factor = math.sqrt((1 - strength) ** 2 + strength ** 2)
|
||||
corrected_noise = mixed_noise / scale_factor
|
||||
|
||||
return mixed_noise
|
||||
return corrected_noise
|
||||
|
||||
# method: incremental seed batch noise
|
||||
if noise_inds is None and incremental_seed_mode == "incremental":
|
||||
@@ -289,48 +255,3 @@ class TaggedCache:
|
||||
def clear(self):
|
||||
# clear all cache
|
||||
self._data = {}
|
||||
|
||||
|
||||
def make_3d_mask(mask):
|
||||
if len(mask.shape) == 4:
|
||||
return mask.squeeze(0)
|
||||
|
||||
elif len(mask.shape) == 2:
|
||||
return mask.unsqueeze(0)
|
||||
|
||||
return mask
|
||||
|
||||
|
||||
def dilate_mask(mask: torch.Tensor, dilation_factor: float) -> torch.Tensor:
|
||||
"""Dilate a mask using a square kernel with a given dilation factor."""
|
||||
kernel_size = int(dilation_factor * 2) + 1
|
||||
kernel = np.ones((abs(kernel_size), abs(kernel_size)), np.uint8)
|
||||
|
||||
masks = make_3d_mask(mask).numpy()
|
||||
dilated_masks = []
|
||||
for m in masks:
|
||||
if dilation_factor > 0:
|
||||
m2 = cv2.dilate(m, kernel, iterations=1)
|
||||
else:
|
||||
m2 = cv2.erode(m, kernel, iterations=1)
|
||||
|
||||
dilated_masks.append(torch.from_numpy(m2))
|
||||
|
||||
return torch.stack(dilated_masks)
|
||||
|
||||
|
||||
def flatten_non_zero_override(masks: torch.Tensor):
|
||||
"""
|
||||
flatten multiple layer mask tensor to 1 layer mask tensor.
|
||||
Override the lower layer with the tensor from the upper layer, but only override non-zero values.
|
||||
|
||||
:param masks: 3d mask
|
||||
:return: flatten mask
|
||||
"""
|
||||
final_mask = masks[0]
|
||||
|
||||
for i in range(1, masks.size(0)):
|
||||
non_zero_mask = masks[i] != 0
|
||||
final_mask[non_zero_mask] = masks[i][non_zero_mask]
|
||||
|
||||
return final_mask
|
||||
|
||||
@@ -572,8 +572,8 @@ class LoraBlockInfo:
|
||||
else:
|
||||
output_blocks_map[k_unet_int] = [k_unet]
|
||||
|
||||
elif k_unet.startswith("er.text_model.encoder.layers."):
|
||||
k_unet_num = k_unet[len("er.text_model.encoder.layers."):len("er.text_model.encoder.layers.")+2]
|
||||
elif k_unet.startswith("_model.encoder.layers."):
|
||||
k_unet_num = k_unet[len("_model.encoder.layers."):len("_model.encoder.layers.")+2]
|
||||
k_unet_int = parse_unet_num(k_unet_num)
|
||||
|
||||
text_block_count.add(k_unet_int)
|
||||
@@ -608,11 +608,12 @@ class LoraBlockInfo:
|
||||
for x in output_keys:
|
||||
text += f" OUT{x}: {len(output_blocks_map[x])}\n"
|
||||
|
||||
text += f"\n-------[Base blocks] ({len(text_block_count) + len(others)}, Subs={len(text_blocks) + len(others)})-------\n"
|
||||
text += f"\n-------[Text blocks] ({len(text_block_count)}, Subs={len(text_blocks)})-------\n"
|
||||
text_keys = sorted(text_blocks_map.keys())
|
||||
for x in text_keys:
|
||||
text += f" TXT_ENC{x}: {len(text_blocks_map[x])}\n"
|
||||
text += f" CLIP{x}: {len(text_blocks_map[x])}\n"
|
||||
|
||||
text += f"\n-------[Base blocks] ({len(others)})-------\n"
|
||||
for x in others:
|
||||
text += f" {x}\n"
|
||||
|
||||
|
||||
+48
-139
@@ -58,8 +58,7 @@ class LoadPromptsFromDir:
|
||||
|
||||
CATEGORY = "InspirePack/Prompt"
|
||||
|
||||
@staticmethod
|
||||
def doit(prompt_dir):
|
||||
def doit(self, prompt_dir):
|
||||
global prompts_path
|
||||
prompt_dir = os.path.join(prompts_path, prompt_dir)
|
||||
files = [f for f in os.listdir(prompt_dir) if f.endswith(".txt")]
|
||||
@@ -105,8 +104,7 @@ class LoadPromptsFromFile:
|
||||
except Exception:
|
||||
prompt_files = []
|
||||
|
||||
return {"required": {"prompt_file": (prompt_files,)},
|
||||
"optional": {"text_data_opt": ("STRING", {"defaultInput": True})}}
|
||||
return {"required": {"prompt_file": (prompt_files,)}}
|
||||
|
||||
RETURN_TYPES = ("ZIPPED_PROMPT",)
|
||||
OUTPUT_IS_LIST = (True,)
|
||||
@@ -115,32 +113,27 @@ class LoadPromptsFromFile:
|
||||
|
||||
CATEGORY = "InspirePack/Prompt"
|
||||
|
||||
@staticmethod
|
||||
def doit(prompt_file, text_data_opt=None):
|
||||
def doit(self, prompt_file):
|
||||
prompt_path = os.path.join(prompts_path, prompt_file)
|
||||
|
||||
prompts = []
|
||||
try:
|
||||
if text_data_opt is None:
|
||||
with open(prompt_path, "r", encoding="utf-8") as file:
|
||||
prompt_data = file.read()
|
||||
else:
|
||||
prompt_data = text_data_opt
|
||||
with open(prompt_path, "r", encoding="utf-8") as file:
|
||||
prompt_data = file.read()
|
||||
prompt_list = re.split(r'\n\s*-+\s*\n', prompt_data)
|
||||
|
||||
prompt_list = re.split(r'\n\s*-+\s*\n', prompt_data)
|
||||
pattern = r"positive:(.*?)(?:\n*|$)negative:(.*)"
|
||||
|
||||
pattern = r"positive:(.*?)(?:\n*|$)negative:(.*)"
|
||||
for prompt in prompt_list:
|
||||
matches = re.search(pattern, prompt, re.DOTALL)
|
||||
|
||||
for prompt in prompt_list:
|
||||
matches = re.search(pattern, prompt, re.DOTALL)
|
||||
|
||||
if matches:
|
||||
positive_text = matches.group(1).strip()
|
||||
negative_text = matches.group(2).strip()
|
||||
result_tuple = (positive_text, negative_text, prompt_file)
|
||||
prompts.append(result_tuple)
|
||||
else:
|
||||
print(f"[WARN] LoadPromptsFromFile: invalid prompt format in '{prompt_file}'")
|
||||
if matches:
|
||||
positive_text = matches.group(1).strip()
|
||||
negative_text = matches.group(2).strip()
|
||||
result_tuple = (positive_text, negative_text, prompt_file)
|
||||
prompts.append(result_tuple)
|
||||
else:
|
||||
print(f"[WARN] LoadPromptsFromFile: invalid prompt format in '{prompt_file}'")
|
||||
except Exception as e:
|
||||
print(f"[ERROR] LoadPromptsFromFile: an error occurred while processing '{prompt_file}': {str(e)}")
|
||||
|
||||
@@ -163,11 +156,10 @@ class LoadSinglePromptFromFile:
|
||||
prompt_files = []
|
||||
|
||||
return {"required": {
|
||||
"prompt_file": (prompt_files,),
|
||||
"index": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||
},
|
||||
"optional": {"text_data_opt": ("STRING", {"defaultInput": True})}
|
||||
}
|
||||
"prompt_file": (prompt_files,),
|
||||
"index": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("ZIPPED_PROMPT",)
|
||||
OUTPUT_IS_LIST = (True,)
|
||||
@@ -176,36 +168,31 @@ class LoadSinglePromptFromFile:
|
||||
|
||||
CATEGORY = "InspirePack/Prompt"
|
||||
|
||||
@staticmethod
|
||||
def doit(prompt_file, index, text_data_opt=None):
|
||||
def doit(self, prompt_file, index):
|
||||
prompt_path = os.path.join(prompts_path, prompt_file)
|
||||
|
||||
prompts = []
|
||||
try:
|
||||
if text_data_opt is None:
|
||||
with open(prompt_path, "r", encoding="utf-8") as file:
|
||||
prompt_data = file.read()
|
||||
else:
|
||||
prompt_data = text_data_opt
|
||||
|
||||
prompt_list = re.split(r'\n\s*-+\s*\n', prompt_data)
|
||||
try:
|
||||
prompt = prompt_list[index]
|
||||
except Exception:
|
||||
prompt = prompt_list[-1]
|
||||
with open(prompt_path, "r", encoding="utf-8") as file:
|
||||
prompt_data = file.read()
|
||||
prompt_list = re.split(r'\n\s*-+\s*\n', prompt_data)
|
||||
try:
|
||||
prompt = prompt_list[index]
|
||||
except Exception:
|
||||
prompt = prompt_list[-1]
|
||||
|
||||
pattern = r"positive:(.*?)(?:\n*|$)negative:(.*)"
|
||||
matches = re.search(pattern, prompt, re.DOTALL)
|
||||
pattern = r"positive:(.*?)(?:\n*|$)negative:(.*)"
|
||||
matches = re.search(pattern, prompt, re.DOTALL)
|
||||
|
||||
if matches:
|
||||
positive_text = matches.group(1).strip()
|
||||
negative_text = matches.group(2).strip()
|
||||
result_tuple = (positive_text, negative_text, prompt_file)
|
||||
prompts.append(result_tuple)
|
||||
else:
|
||||
print(f"[WARN] LoadSinglePromptFromFile: invalid prompt format in '{prompt_file}'")
|
||||
if matches:
|
||||
positive_text = matches.group(1).strip()
|
||||
negative_text = matches.group(2).strip()
|
||||
result_tuple = (positive_text, negative_text, prompt_file)
|
||||
prompts.append(result_tuple)
|
||||
else:
|
||||
print(f"[WARN] LoadPromptsFromFile: invalid prompt format in '{prompt_file}'")
|
||||
except Exception as e:
|
||||
print(f"[ERROR] LoadSinglePromptFromFile: an error occurred while processing '{prompt_file}': {str(e)}")
|
||||
print(f"[ERROR] LoadPromptsFromFile: an error occurred while processing '{prompt_file}': {str(e)}")
|
||||
|
||||
return (prompts, )
|
||||
|
||||
@@ -248,8 +235,9 @@ class ZipPrompt:
|
||||
return ((positive, negative, name_opt), )
|
||||
|
||||
|
||||
prompt_blacklist = set(['filename_prefix'])
|
||||
|
||||
prompt_blacklist = set([
|
||||
'filename_prefix'
|
||||
])
|
||||
|
||||
class PromptExtractor:
|
||||
@classmethod
|
||||
@@ -561,12 +549,7 @@ class SeedExplorer:
|
||||
"additional_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"noise_mode": (["GPU(=A1111)", "CPU"],),
|
||||
"initial_batch_seed_mode": (["incremental", "comfy"],),
|
||||
},
|
||||
"optional":
|
||||
{
|
||||
"variation_method": (["linear", "slerp"],),
|
||||
"model": ("model",),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("NOISE",)
|
||||
@@ -575,7 +558,7 @@ class SeedExplorer:
|
||||
CATEGORY = "InspirePack/Prompt"
|
||||
|
||||
@staticmethod
|
||||
def apply_variation(start_noise, seed_items, noise_device, mask=None, variation_method='linear'):
|
||||
def apply_variation(start_noise, seed_items, noise_device, mask=None):
|
||||
noise = start_noise
|
||||
for x in seed_items:
|
||||
if isinstance(x, str):
|
||||
@@ -588,20 +571,15 @@ class SeedExplorer:
|
||||
variation_seed = int(item[0])
|
||||
variation_strength = float(item[1])
|
||||
|
||||
noise = utils.apply_variation_noise(noise, noise_device, variation_seed, variation_strength, mask=mask, variation_method=variation_method)
|
||||
noise = utils.apply_variation_noise(noise, noise_device, variation_seed, variation_strength, mask=mask)
|
||||
except Exception:
|
||||
print(f"[ERROR] IGNORED: SeedExplorer failed to processing '{x}'")
|
||||
traceback.print_exc()
|
||||
return noise
|
||||
|
||||
@staticmethod
|
||||
def doit(latent, seed_prompt, enable_additional, additional_seed, additional_strength, noise_mode,
|
||||
initial_batch_seed_mode, variation_method='linear', model=None):
|
||||
def doit(self, latent, seed_prompt, enable_additional, additional_seed, additional_strength, noise_mode,
|
||||
initial_batch_seed_mode):
|
||||
latent_image = latent["samples"]
|
||||
|
||||
if hasattr(comfy.sample, 'fix_empty_latent_channels') and model is not None:
|
||||
latent_image = comfy.sample.fix_empty_latent_channels(model, latent_image)
|
||||
|
||||
device = comfy.model_management.get_torch_device()
|
||||
noise_device = "cpu" if noise_mode == "CPU" else device
|
||||
|
||||
@@ -625,7 +603,7 @@ class SeedExplorer:
|
||||
|
||||
noise = utils.prepare_noise(latent_image, hd_seed, None, noise_device, initial_batch_seed_mode)
|
||||
noise = noise.to(device)
|
||||
noise = SeedExplorer.apply_variation(noise, tl, noise_device, variation_method=variation_method)
|
||||
noise = SeedExplorer.apply_variation(noise, tl, noise_device)
|
||||
noise = noise.cpu()
|
||||
|
||||
return (noise,)
|
||||
@@ -639,72 +617,6 @@ class SeedExplorer:
|
||||
return (noise,)
|
||||
|
||||
|
||||
class CompositeNoise:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"destination": ("NOISE",),
|
||||
"source": ("NOISE",),
|
||||
"mode": (["center", "left-top", "right-top", "left-bottom", "right-bottom", "xy"], ),
|
||||
"x": ("INT", {"default": 0, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
|
||||
"y": ("INT", {"default": 0, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("NOISE",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "InspirePack/Prompt"
|
||||
|
||||
def doit(self, destination, source, mode, x, y):
|
||||
new_tensor = destination.clone()
|
||||
|
||||
if mode == 'center':
|
||||
y1 = (new_tensor.size(2) - source.size(2)) // 2
|
||||
x1 = (new_tensor.size(3) - source.size(3)) // 2
|
||||
elif mode == 'left-top':
|
||||
y1 = 0
|
||||
x1 = 0
|
||||
elif mode == 'right-top':
|
||||
y1 = 0
|
||||
x1 = new_tensor.size(2) - source.size(2)
|
||||
elif mode == 'left-bottom':
|
||||
y1 = new_tensor.size(3) - source.size(3)
|
||||
x1 = 0
|
||||
elif mode == 'right-bottom':
|
||||
y1 = new_tensor.size(3) - source.size(3)
|
||||
x1 = new_tensor.size(2) - source.size(2)
|
||||
else: # mode == 'xy':
|
||||
x1 = max(0, x)
|
||||
y1 = max(0, y)
|
||||
|
||||
# raw coordinates
|
||||
y2 = y1 + source.size(2)
|
||||
x2 = x1 + source.size(3)
|
||||
|
||||
# bounding for destination
|
||||
top = max(0, y1)
|
||||
left = max(0, x1)
|
||||
bottom = min(new_tensor.size(2), y2)
|
||||
right = min(new_tensor.size(3), x2)
|
||||
|
||||
# bounding for source
|
||||
left_gap = left - x1
|
||||
top_gap = top - y1
|
||||
|
||||
width = right - left
|
||||
height = bottom - top
|
||||
|
||||
height = min(height, y1 + source.size(2) - top)
|
||||
width = min(width, x1 + source.size(3) - left)
|
||||
|
||||
# composite
|
||||
new_tensor[:, :, top:top + height, left:left + width] = source[:, :, top_gap:top_gap + height, left_gap:left_gap + width]
|
||||
|
||||
return (new_tensor,)
|
||||
|
||||
|
||||
list_counter_map = {}
|
||||
|
||||
|
||||
@@ -856,9 +768,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"MakeBasicPipe //Inspire": MakeBasicPipe,
|
||||
"RemoveControlNet //Inspire": RemoveControlNet,
|
||||
"RemoveControlNetFromRegionalPrompts //Inspire": RemoveControlNetFromRegionalPrompts,
|
||||
"CompositeNoise //Inspire": CompositeNoise
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"LoadPromptsFromDir //Inspire": "Load Prompts From Dir (Inspire)",
|
||||
"LoadPromptsFromFile //Inspire": "Load Prompts From File (Inspire)",
|
||||
@@ -877,6 +787,5 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"RandomGeneratorForList //Inspire": "Random Generator for List (Inspire)",
|
||||
"MakeBasicPipe //Inspire": "Make Basic Pipe (Inspire)",
|
||||
"RemoveControlNet //Inspire": "Remove ControlNet (Inspire)",
|
||||
"RemoveControlNetFromRegionalPrompts //Inspire": "Remove ControlNet [RegionalPrompts] (Inspire)",
|
||||
"CompositeNoise //Inspire": "Composite Noise (Inspire)"
|
||||
"RemoveControlNetFromRegionalPrompts //Inspire": "Remove ControlNet [RegionalPrompts] (Inspire)"
|
||||
}
|
||||
|
||||
+25
-181
@@ -3,8 +3,6 @@ import traceback
|
||||
import comfy
|
||||
import nodes
|
||||
import torch
|
||||
import re
|
||||
|
||||
from . import prompt_support
|
||||
from .libs import utils, common
|
||||
|
||||
@@ -23,12 +21,6 @@ class RegionalPromptSimple:
|
||||
"controlnet_in_pipe": ("BOOLEAN", {"default": False, "label_on": "Keep", "label_off": "Override"}),
|
||||
"sigma_factor": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
|
||||
},
|
||||
"optional": {
|
||||
"variation_seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||
"variation_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"variation_method": (["linear", "slerp"],),
|
||||
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("REGIONAL_PROMPTS", )
|
||||
@@ -36,9 +28,7 @@ class RegionalPromptSimple:
|
||||
|
||||
CATEGORY = "InspirePack/Regional"
|
||||
|
||||
@staticmethod
|
||||
def doit(basic_pipe, mask, cfg, sampler_name, scheduler, wildcard_prompt,
|
||||
controlnet_in_pipe=False, sigma_factor=1.0, variation_seed=0, variation_strength=0.0, variation_method='linear', scheduler_func_opt=None):
|
||||
def doit(self, basic_pipe, mask, cfg, sampler_name, scheduler, wildcard_prompt, controlnet_in_pipe=False, sigma_factor=1.0):
|
||||
if 'RegionalPrompt' not in nodes.NODE_CLASS_MAPPINGS:
|
||||
utils.try_install_custom_node('https://github.com/ltdrdata/ComfyUI-Impact-Pack',
|
||||
"To use 'RegionalPromptSimple' node, 'Impact Pack' extension is required.")
|
||||
@@ -51,7 +41,7 @@ class RegionalPromptSimple:
|
||||
rp = nodes.NODE_CLASS_MAPPINGS['RegionalPrompt']()
|
||||
|
||||
if wildcard_prompt != "":
|
||||
model, clip, new_positive, _ = iwe.doit(model=model, clip=clip, populated_text=wildcard_prompt, seed=None)
|
||||
model, clip, new_positive, _ = iwe.doit(model=model, clip=clip, populated_text=wildcard_prompt)
|
||||
|
||||
if controlnet_in_pipe:
|
||||
prev_cnet = None
|
||||
@@ -70,11 +60,8 @@ class RegionalPromptSimple:
|
||||
|
||||
basic_pipe = model, clip, vae, new_positive, negative
|
||||
|
||||
sampler = kap.doit(cfg, sampler_name, scheduler, basic_pipe, sigma_factor=sigma_factor, scheduler_func_opt=scheduler_func_opt)[0]
|
||||
try:
|
||||
regional_prompts = rp.doit(mask, sampler, variation_seed=variation_seed, variation_strength=variation_strength, variation_method=variation_method)[0]
|
||||
except:
|
||||
raise Exception("[Inspire-Pack] ERROR: Impact Pack is outdated. Update Impact Pack to latest version to use this.")
|
||||
sampler = kap.doit(cfg, sampler_name, scheduler, basic_pipe, sigma_factor=sigma_factor)[0]
|
||||
regional_prompts = rp.doit(mask, sampler)[0]
|
||||
|
||||
return (regional_prompts, )
|
||||
|
||||
@@ -109,12 +96,6 @@ class RegionalPromptColorMask:
|
||||
"controlnet_in_pipe": ("BOOLEAN", {"default": False, "label_on": "Keep", "label_off": "Override"}),
|
||||
"sigma_factor": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
|
||||
},
|
||||
"optional": {
|
||||
"variation_seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||
"variation_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"variation_method": (["linear", "slerp"],),
|
||||
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("REGIONAL_PROMPTS", "MASK")
|
||||
@@ -122,13 +103,10 @@ class RegionalPromptColorMask:
|
||||
|
||||
CATEGORY = "InspirePack/Regional"
|
||||
|
||||
@staticmethod
|
||||
def doit(basic_pipe, color_mask, mask_color, cfg, sampler_name, scheduler, wildcard_prompt,
|
||||
controlnet_in_pipe=False, sigma_factor=1.0, variation_seed=0, variation_strength=0.0, variation_method="linear", scheduler_func_opt=None):
|
||||
def doit(self, basic_pipe, color_mask, mask_color, cfg, sampler_name, scheduler, wildcard_prompt, controlnet_in_pipe=False, sigma_factor=1.0):
|
||||
mask = color_to_mask(color_mask, mask_color)
|
||||
rp = RegionalPromptSimple().doit(basic_pipe, mask, cfg, sampler_name, scheduler, wildcard_prompt, controlnet_in_pipe,
|
||||
sigma_factor=sigma_factor, variation_seed=variation_seed, variation_strength=variation_strength, variation_method=variation_method, scheduler_func_opt=scheduler_func_opt)[0]
|
||||
return rp, mask
|
||||
rp = RegionalPromptSimple().doit(basic_pipe, mask, cfg, sampler_name, scheduler, wildcard_prompt, controlnet_in_pipe, sigma_factor=sigma_factor)[0]
|
||||
return (rp, mask)
|
||||
|
||||
|
||||
class RegionalConditioningSimple:
|
||||
@@ -149,8 +127,7 @@ class RegionalConditioningSimple:
|
||||
|
||||
CATEGORY = "InspirePack/Regional"
|
||||
|
||||
@staticmethod
|
||||
def doit(clip, mask, strength, set_cond_area, prompt):
|
||||
def doit(self, clip, mask, strength, set_cond_area, prompt):
|
||||
conditioning = nodes.CLIPTextEncode().encode(clip, prompt)[0]
|
||||
conditioning = nodes.ConditioningSetMask().append(conditioning, mask, set_cond_area, strength)[0]
|
||||
return (conditioning, )
|
||||
@@ -168,9 +145,6 @@ class RegionalConditioningColorMask:
|
||||
"set_cond_area": (["default", "mask bounds"],),
|
||||
"prompt": ("STRING", {"multiline": True, "placeholder": "prompt"}),
|
||||
},
|
||||
"optional": {
|
||||
"dilation": ("INT", {"default": 0, "min": -512, "max": 512, "step": 1}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("CONDITIONING", "MASK")
|
||||
@@ -178,16 +152,12 @@ class RegionalConditioningColorMask:
|
||||
|
||||
CATEGORY = "InspirePack/Regional"
|
||||
|
||||
@staticmethod
|
||||
def doit(clip, color_mask, mask_color, strength, set_cond_area, prompt, dilation=0):
|
||||
def doit(self, clip, color_mask, mask_color, strength, set_cond_area, prompt):
|
||||
mask = color_to_mask(color_mask, mask_color)
|
||||
|
||||
if dilation != 0:
|
||||
mask = utils.dilate_mask(mask, dilation)
|
||||
|
||||
conditioning = nodes.CLIPTextEncode().encode(clip, prompt)[0]
|
||||
conditioning = nodes.ConditioningSetMask().append(conditioning, mask, set_cond_area, strength)[0]
|
||||
return conditioning, mask
|
||||
return (conditioning, mask)
|
||||
|
||||
|
||||
class ToIPAdapterPipe:
|
||||
@@ -209,8 +179,7 @@ class ToIPAdapterPipe:
|
||||
|
||||
CATEGORY = "InspirePack/Util"
|
||||
|
||||
@staticmethod
|
||||
def doit(ipadapter, model, clip_vision, insightface=None):
|
||||
def doit(self, ipadapter, model, clip_vision, insightface=None):
|
||||
pipe = ipadapter, model, clip_vision, insightface, lambda x: x
|
||||
|
||||
return (pipe,)
|
||||
@@ -275,22 +244,6 @@ class IPAdapterConditioning:
|
||||
return model
|
||||
|
||||
|
||||
IPADAPTER_WEIGHT_TYPES_CACHE = None
|
||||
|
||||
|
||||
def IPADAPTER_WEIGHT_TYPES():
|
||||
global IPADAPTER_WEIGHT_TYPES_CACHE
|
||||
|
||||
if IPADAPTER_WEIGHT_TYPES_CACHE is None:
|
||||
try:
|
||||
IPADAPTER_WEIGHT_TYPES_CACHE = nodes.NODE_CLASS_MAPPINGS['IPAdapterAdvanced']().INPUT_TYPES()['required']['weight_type'][0]
|
||||
except Exception:
|
||||
print(f"[Inspire Pack] IPAdapterPlus is not installed.")
|
||||
IPADAPTER_WEIGHT_TYPES_CACHE = ["IPAdapterPlus is not installed"]
|
||||
|
||||
return IPADAPTER_WEIGHT_TYPES_CACHE
|
||||
|
||||
|
||||
class RegionalIPAdapterMask:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
@@ -301,7 +254,7 @@ class RegionalIPAdapterMask:
|
||||
"image": ("IMAGE",),
|
||||
"weight": ("FLOAT", {"default": 0.7, "min": -1, "max": 3, "step": 0.05}),
|
||||
"noise": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"weight_type": (IPADAPTER_WEIGHT_TYPES(), ),
|
||||
"weight_type": (["original", "linear", "channel penalty"],),
|
||||
"start_at": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}),
|
||||
"end_at": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}),
|
||||
"unfold_batch": ("BOOLEAN", {"default": False}),
|
||||
@@ -319,8 +272,7 @@ class RegionalIPAdapterMask:
|
||||
|
||||
CATEGORY = "InspirePack/Regional"
|
||||
|
||||
@staticmethod
|
||||
def doit(mask, image, weight, noise, weight_type, start_at=0.0, end_at=1.0, unfold_batch=False, faceid_v2=False, weight_v2=False, combine_embeds="concat", neg_image=None):
|
||||
def doit(self, mask, image, weight, noise, weight_type, start_at=0.0, end_at=1.0, unfold_batch=False, faceid_v2=False, weight_v2=False, combine_embeds="concat", neg_image=None):
|
||||
cond = IPAdapterConditioning(mask, weight, weight_type, noise=noise, image=image, neg_image=neg_image, start_at=start_at, end_at=end_at, unfold_batch=unfold_batch, weight_v2=weight_v2, combine_embeds=combine_embeds)
|
||||
return (cond, )
|
||||
|
||||
@@ -336,7 +288,7 @@ class RegionalIPAdapterColorMask:
|
||||
"image": ("IMAGE",),
|
||||
"weight": ("FLOAT", {"default": 0.7, "min": -1, "max": 3, "step": 0.05}),
|
||||
"noise": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"weight_type": (IPADAPTER_WEIGHT_TYPES(), ),
|
||||
"weight_type": (["original", "linear", "channel penalty"], ),
|
||||
"start_at": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}),
|
||||
"end_at": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}),
|
||||
"unfold_batch": ("BOOLEAN", {"default": False}),
|
||||
@@ -354,8 +306,7 @@ class RegionalIPAdapterColorMask:
|
||||
|
||||
CATEGORY = "InspirePack/Regional"
|
||||
|
||||
@staticmethod
|
||||
def doit(color_mask, mask_color, image, weight, noise, weight_type, start_at=0.0, end_at=1.0, unfold_batch=False, faceid_v2=False, weight_v2=False, combine_embeds="concat", neg_image=None):
|
||||
def doit(self, color_mask, mask_color, image, weight, noise, weight_type, start_at=0.0, end_at=1.0, unfold_batch=False, faceid_v2=False, weight_v2=False, combine_embeds="concat", neg_image=None):
|
||||
mask = color_to_mask(color_mask, mask_color)
|
||||
cond = IPAdapterConditioning(mask, weight, weight_type, noise=noise, image=image, neg_image=neg_image, start_at=start_at, end_at=end_at, unfold_batch=unfold_batch, weight_v2=weight_v2, combine_embeds=combine_embeds)
|
||||
return (cond, mask)
|
||||
@@ -370,7 +321,7 @@ class RegionalIPAdapterEncodedMask:
|
||||
|
||||
"embeds": ("EMBEDS",),
|
||||
"weight": ("FLOAT", {"default": 0.7, "min": -1, "max": 3, "step": 0.05}),
|
||||
"weight_type": (IPADAPTER_WEIGHT_TYPES(), ),
|
||||
"weight_type": (["original", "linear", "channel penalty"],),
|
||||
"start_at": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}),
|
||||
"end_at": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}),
|
||||
"unfold_batch": ("BOOLEAN", {"default": False}),
|
||||
@@ -385,8 +336,7 @@ class RegionalIPAdapterEncodedMask:
|
||||
|
||||
CATEGORY = "InspirePack/Regional"
|
||||
|
||||
@staticmethod
|
||||
def doit(mask, embeds, weight, weight_type, start_at=0.0, end_at=1.0, unfold_batch=False, neg_embeds=None):
|
||||
def doit(self, mask, embeds, weight, weight_type, start_at=0.0, end_at=1.0, unfold_batch=False, neg_embeds=None):
|
||||
cond = IPAdapterConditioning(mask, weight, weight_type, embeds=embeds, start_at=start_at, end_at=end_at, unfold_batch=unfold_batch, neg_embeds=neg_embeds)
|
||||
return (cond, )
|
||||
|
||||
@@ -401,7 +351,7 @@ class RegionalIPAdapterEncodedColorMask:
|
||||
|
||||
"embeds": ("EMBEDS",),
|
||||
"weight": ("FLOAT", {"default": 0.7, "min": -1, "max": 3, "step": 0.05}),
|
||||
"weight_type": (IPADAPTER_WEIGHT_TYPES(), ),
|
||||
"weight_type": (["original", "linear", "channel penalty"],),
|
||||
"start_at": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}),
|
||||
"end_at": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}),
|
||||
"unfold_batch": ("BOOLEAN", {"default": False}),
|
||||
@@ -416,8 +366,7 @@ class RegionalIPAdapterEncodedColorMask:
|
||||
|
||||
CATEGORY = "InspirePack/Regional"
|
||||
|
||||
@staticmethod
|
||||
def doit(color_mask, mask_color, embeds, weight, weight_type, start_at=0.0, end_at=1.0, unfold_batch=False, neg_embeds=None):
|
||||
def doit(self, color_mask, mask_color, embeds, weight, weight_type, start_at=0.0, end_at=1.0, unfold_batch=False, neg_embeds=None):
|
||||
mask = color_to_mask(color_mask, mask_color)
|
||||
cond = IPAdapterConditioning(mask, weight, weight_type, embeds=embeds, start_at=start_at, end_at=end_at, unfold_batch=unfold_batch, neg_embeds=neg_embeds)
|
||||
return (cond, mask)
|
||||
@@ -437,8 +386,7 @@ class ApplyRegionalIPAdapters:
|
||||
|
||||
CATEGORY = "InspirePack/Regional"
|
||||
|
||||
@staticmethod
|
||||
def doit(**kwargs):
|
||||
def doit(self, **kwargs):
|
||||
ipadapter_pipe = kwargs['ipadapter_pipe']
|
||||
ipadapter, model, clip_vision, insightface, lora_loader = ipadapter_pipe
|
||||
|
||||
@@ -465,8 +413,6 @@ class RegionalSeedExplorerMask:
|
||||
"additional_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"noise_mode": (["GPU(=A1111)", "CPU"],),
|
||||
},
|
||||
"optional":
|
||||
{"variation_method": (["linear", "slerp"],), }
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("NOISE",)
|
||||
@@ -474,8 +420,7 @@ class RegionalSeedExplorerMask:
|
||||
|
||||
CATEGORY = "InspirePack/Regional"
|
||||
|
||||
@staticmethod
|
||||
def doit(mask, noise, seed_prompt, enable_additional, additional_seed, additional_strength, noise_mode, variation_method='linear'):
|
||||
def doit(self, mask, noise, seed_prompt, enable_additional, additional_seed, additional_strength, noise_mode):
|
||||
device = comfy.model_management.get_torch_device()
|
||||
noise_device = "cpu" if noise_mode == "CPU" else device
|
||||
|
||||
@@ -497,7 +442,7 @@ class RegionalSeedExplorerMask:
|
||||
if enable_additional:
|
||||
items.append((additional_seed, additional_strength))
|
||||
|
||||
noise = prompt_support.SeedExplorer.apply_variation(noise, items, noise_device, mask, variation_method=variation_method)
|
||||
noise = prompt_support.SeedExplorer.apply_variation(noise, items, noise_device, mask)
|
||||
except Exception:
|
||||
print(f"[ERROR] IGNORED: RegionalSeedExplorerColorMask is failed.")
|
||||
traceback.print_exc()
|
||||
@@ -522,8 +467,6 @@ class RegionalSeedExplorerColorMask:
|
||||
"additional_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"noise_mode": (["GPU(=A1111)", "CPU"],),
|
||||
},
|
||||
"optional":
|
||||
{"variation_method": (["linear", "slerp"],), }
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("NOISE", "MASK")
|
||||
@@ -531,8 +474,7 @@ class RegionalSeedExplorerColorMask:
|
||||
|
||||
CATEGORY = "InspirePack/Regional"
|
||||
|
||||
@staticmethod
|
||||
def doit(color_mask, mask_color, noise, seed_prompt, enable_additional, additional_seed, additional_strength, noise_mode, variation_method='linear'):
|
||||
def doit(self, color_mask, mask_color, noise, seed_prompt, enable_additional, additional_seed, additional_strength, noise_mode):
|
||||
device = comfy.model_management.get_torch_device()
|
||||
noise_device = "cpu" if noise_mode == "CPU" else device
|
||||
|
||||
@@ -555,7 +497,7 @@ class RegionalSeedExplorerColorMask:
|
||||
if enable_additional:
|
||||
items.append((additional_seed, additional_strength))
|
||||
|
||||
noise = prompt_support.SeedExplorer.apply_variation(noise, items, noise_device, mask, variation_method=variation_method)
|
||||
noise = prompt_support.SeedExplorer.apply_variation(noise, items, noise_device, mask)
|
||||
except Exception:
|
||||
print(f"[ERROR] IGNORED: RegionalSeedExplorerColorMask is failed.")
|
||||
traceback.print_exc()
|
||||
@@ -566,100 +508,6 @@ class RegionalSeedExplorerColorMask:
|
||||
return (noise, original_mask)
|
||||
|
||||
|
||||
class ColorMaskToDepthMask:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"color_mask": ("IMAGE",),
|
||||
"spec": ("STRING", {"multiline": True, "default": "#FF0000:1.0\n#000000:1.0"}),
|
||||
"base_value": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0}),
|
||||
"dilation": ("INT", {"default": 0, "min": -512, "max": 512, "step": 1}),
|
||||
"flatten_method": (["override", "sum", "max"],),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("MASK", )
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "InspirePack/Regional"
|
||||
|
||||
def doit(self, color_mask, spec, base_value, dilation, flatten_method):
|
||||
specs = spec.split('\n')
|
||||
pat = re.compile("(?P<color_code>#[A-F0-9]+):(?P<cfg>[0-9]+(.[0-9]*)?)")
|
||||
|
||||
masks = [torch.ones((1, color_mask.shape[1], color_mask.shape[2])) * base_value]
|
||||
for x in specs:
|
||||
match = pat.match(x)
|
||||
if match:
|
||||
mask = color_to_mask(color_mask=color_mask, mask_color=match['color_code']) * float(match['cfg'])
|
||||
mask = utils.dilate_mask(mask, dilation)
|
||||
masks.append(mask)
|
||||
|
||||
if masks:
|
||||
masks = torch.cat(masks, dim=0)
|
||||
if flatten_method == 'override':
|
||||
masks = utils.flatten_non_zero_override(masks)
|
||||
elif flatten_method == 'max':
|
||||
masks = torch.max(masks, dim=0)[0]
|
||||
else: # flatten_method == 'sum':
|
||||
masks = torch.sum(masks, dim=0)
|
||||
|
||||
masks = torch.clamp(masks, min=0.0, max=1.0)
|
||||
masks = masks.unsqueeze(0)
|
||||
else:
|
||||
masks = torch.tensor([])
|
||||
|
||||
return (masks, )
|
||||
|
||||
|
||||
class RegionalCFG:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {"model": ("MODEL",),
|
||||
"mask": ("MASK",),
|
||||
}}
|
||||
|
||||
RETURN_TYPES = ("MODEL",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "InspirePack/Regional"
|
||||
|
||||
@staticmethod
|
||||
def doit(model, mask):
|
||||
if len(mask.shape) == 2:
|
||||
mask = mask.unsqueeze(0).unsqueeze(0)
|
||||
elif len(mask.shape) == 3:
|
||||
mask = mask.unsqueeze(0)
|
||||
|
||||
size = None
|
||||
|
||||
def regional_cfg(args):
|
||||
nonlocal mask
|
||||
nonlocal size
|
||||
|
||||
x = args['input']
|
||||
|
||||
if mask.device != x.device:
|
||||
mask = mask.to(x.device)
|
||||
|
||||
if size != (x.shape[2], x.shape[3]):
|
||||
size = (x.shape[2], x.shape[3])
|
||||
mask = torch.nn.functional.interpolate(mask, size=size, mode='bilinear', align_corners=False)
|
||||
|
||||
cond_pred = args["cond_denoised"]
|
||||
uncond_pred = args["uncond_denoised"]
|
||||
cond_scale = args["cond_scale"]
|
||||
|
||||
cfg_result = uncond_pred + (cond_pred - uncond_pred) * cond_scale * mask
|
||||
|
||||
return x - cfg_result
|
||||
|
||||
m = model.clone()
|
||||
m.set_model_sampler_cfg_function(regional_cfg)
|
||||
return (m,)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"RegionalPromptSimple //Inspire": RegionalPromptSimple,
|
||||
"RegionalPromptColorMask //Inspire": RegionalPromptColorMask,
|
||||
@@ -674,8 +522,6 @@ NODE_CLASS_MAPPINGS = {
|
||||
"ToIPAdapterPipe //Inspire": ToIPAdapterPipe,
|
||||
"FromIPAdapterPipe //Inspire": FromIPAdapterPipe,
|
||||
"ApplyRegionalIPAdapters //Inspire": ApplyRegionalIPAdapters,
|
||||
"RegionalCFG //Inspire": RegionalCFG,
|
||||
"ColorMaskToDepthMask //Inspire": ColorMaskToDepthMask,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
@@ -691,7 +537,5 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"RegionalSeedExplorerColorMask //Inspire": "Regional Seed Explorer By Color Mask (Inspire)",
|
||||
"ToIPAdapterPipe //Inspire": "ToIPAdapterPipe (Inspire)",
|
||||
"FromIPAdapterPipe //Inspire": "FromIPAdapterPipe (Inspire)",
|
||||
"ApplyRegionalIPAdapters //Inspire": "Apply Regional IPAdapters (Inspire)",
|
||||
"RegionalCFG //Inspire": "Regional CFG (Inspire)",
|
||||
"ColorMaskToDepthMask //Inspire": "Color Mask To Depth Mask (Inspire)",
|
||||
"ApplyRegionalIPAdapters //Inspire": "Apply Regional IPAdapters (Inspire)"
|
||||
}
|
||||
|
||||
+45
-251
@@ -3,31 +3,26 @@ from . import a1111_compat
|
||||
import comfy
|
||||
from .libs import common
|
||||
from comfy import model_management
|
||||
from comfy.samplers import CFGGuider
|
||||
from comfy_extras.nodes_perpneg import Guider_PerpNeg
|
||||
import math
|
||||
|
||||
|
||||
class KSampler_progress(a1111_compat.KSampler_inspire):
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"model": ("MODEL",),
|
||||
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||
"steps": ("INT", {"default": 20, "min": 1, "max": 10000}),
|
||||
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}),
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, ),
|
||||
"scheduler": (common.SCHEDULERS, ),
|
||||
"positive": ("CONDITIONING", ),
|
||||
"negative": ("CONDITIONING", ),
|
||||
"latent_image": ("LATENT", ),
|
||||
"denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"noise_mode": (["GPU(=A1111)", "CPU"],),
|
||||
"interval": ("INT", {"default": 1, "min": 1, "max": 10000}),
|
||||
"omit_start_latent": ("BOOLEAN", {"default": True, "label_on": "True", "label_off": "False"}),
|
||||
},
|
||||
"optional": {
|
||||
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
||||
}
|
||||
return {"required":
|
||||
{"model": ("MODEL",),
|
||||
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||
"steps": ("INT", {"default": 20, "min": 1, "max": 10000}),
|
||||
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}),
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, ),
|
||||
"scheduler": (common.SCHEDULERS, ),
|
||||
"positive": ("CONDITIONING", ),
|
||||
"negative": ("CONDITIONING", ),
|
||||
"latent_image": ("LATENT", ),
|
||||
"denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"noise_mode": (["GPU(=A1111)", "CPU"],),
|
||||
"interval": ("INT", {"default": 1, "min": 1, "max": 10000}),
|
||||
"omit_start_latent": ("BOOLEAN", {"default": True, "label_on": "True", "label_off": "False"}),
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = "InspirePack/analysis"
|
||||
@@ -35,8 +30,7 @@ class KSampler_progress(a1111_compat.KSampler_inspire):
|
||||
RETURN_TYPES = ("LATENT", "LATENT")
|
||||
RETURN_NAMES = ("latent", "progress_latent")
|
||||
|
||||
@staticmethod
|
||||
def doit(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise, noise_mode, interval, omit_start_latent, scheduler_func_opt=None):
|
||||
def doit(self, model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, denoise, noise_mode, interval, omit_start_latent):
|
||||
adv_steps = int(steps / denoise)
|
||||
|
||||
if omit_start_latent:
|
||||
@@ -47,15 +41,11 @@ class KSampler_progress(a1111_compat.KSampler_inspire):
|
||||
result = []
|
||||
|
||||
def progress_callback(step, x0, x, total_steps):
|
||||
if (total_steps-1) != step and step % interval != 0:
|
||||
return
|
||||
x0 = model.model.process_latent_out(x0)
|
||||
x0 = x0.to(model_management.intermediate_device())
|
||||
result.append(x0)
|
||||
|
||||
x = model.model.process_latent_out(x)
|
||||
x = x.to(model_management.intermediate_device())
|
||||
result.append(x)
|
||||
|
||||
latent_image, noise = a1111_compat.KSamplerAdvanced_inspire.sample(model, True, seed, adv_steps, cfg, sampler_name, scheduler, positive, negative, latent_image, (adv_steps-steps),
|
||||
adv_steps, noise_mode, False, callback=progress_callback, scheduler_func_opt=scheduler_func_opt)
|
||||
latent_image, noise = a1111_compat.KSamplerAdvanced_inspire.sample(model, True, seed, adv_steps, cfg, sampler_name, scheduler, positive, negative, latent_image, (adv_steps-steps), adv_steps, noise_mode, False, callback=progress_callback)
|
||||
|
||||
if len(result) > 0:
|
||||
result = torch.cat(result)
|
||||
@@ -69,28 +59,25 @@ class KSampler_progress(a1111_compat.KSampler_inspire):
|
||||
class KSamplerAdvanced_progress(a1111_compat.KSamplerAdvanced_inspire):
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"model": ("MODEL",),
|
||||
"add_noise": ("BOOLEAN", {"default": True, "label_on": "enable", "label_off": "disable"}),
|
||||
"noise_seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||
"steps": ("INT", {"default": 20, "min": 1, "max": 10000}),
|
||||
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step":0.5, "round": 0.01}),
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, ),
|
||||
"scheduler": (common.SCHEDULERS, ),
|
||||
"positive": ("CONDITIONING", ),
|
||||
"negative": ("CONDITIONING", ),
|
||||
"latent_image": ("LATENT", ),
|
||||
"start_at_step": ("INT", {"default": 0, "min": 0, "max": 10000}),
|
||||
"end_at_step": ("INT", {"default": 10000, "min": 0, "max": 10000}),
|
||||
"noise_mode": (["GPU(=A1111)", "CPU"],),
|
||||
"return_with_leftover_noise": ("BOOLEAN", {"default": False, "label_on": "enable", "label_off": "disable"}),
|
||||
"interval": ("INT", {"default": 1, "min": 1, "max": 10000}),
|
||||
"omit_start_latent": ("BOOLEAN", {"default": False, "label_on": "True", "label_off": "False"}),
|
||||
},
|
||||
"optional": {
|
||||
"prev_progress_latent_opt": ("LATENT",),
|
||||
"scheduler_func_opt": ("SCHEDULER_FUNC",),
|
||||
}
|
||||
return {"required":
|
||||
{"model": ("MODEL",),
|
||||
"add_noise": ("BOOLEAN", {"default": True, "label_on": "enable", "label_off": "disable"}),
|
||||
"noise_seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||
"steps": ("INT", {"default": 20, "min": 1, "max": 10000}),
|
||||
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step":0.5, "round": 0.01}),
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, ),
|
||||
"scheduler": (common.SCHEDULERS, ),
|
||||
"positive": ("CONDITIONING", ),
|
||||
"negative": ("CONDITIONING", ),
|
||||
"latent_image": ("LATENT", ),
|
||||
"start_at_step": ("INT", {"default": 0, "min": 0, "max": 10000}),
|
||||
"end_at_step": ("INT", {"default": 10000, "min": 0, "max": 10000}),
|
||||
"noise_mode": (["GPU(=A1111)", "CPU"],),
|
||||
"return_with_leftover_noise": ("BOOLEAN", {"default": False, "label_on": "enable", "label_off": "disable"}),
|
||||
"interval": ("INT", {"default": 1, "min": 1, "max": 10000}),
|
||||
"omit_start_latent": ("BOOLEAN", {"default": False, "label_on": "True", "label_off": "False"}),
|
||||
},
|
||||
"optional": {"prev_progress_latent_opt": ("LATENT",), }
|
||||
}
|
||||
|
||||
FUNCTION = "doit"
|
||||
@@ -101,7 +88,7 @@ class KSamplerAdvanced_progress(a1111_compat.KSamplerAdvanced_inspire):
|
||||
RETURN_NAMES = ("latent", "progress_latent")
|
||||
|
||||
def doit(self, model, add_noise, noise_seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step,
|
||||
noise_mode, return_with_leftover_noise, interval, omit_start_latent, prev_progress_latent_opt=None, scheduler_func_opt=None):
|
||||
noise_mode, return_with_leftover_noise, interval, omit_start_latent, prev_progress_latent_opt=None):
|
||||
if omit_start_latent:
|
||||
result = []
|
||||
else:
|
||||
@@ -110,15 +97,12 @@ class KSamplerAdvanced_progress(a1111_compat.KSamplerAdvanced_inspire):
|
||||
result = []
|
||||
|
||||
def progress_callback(step, x0, x, total_steps):
|
||||
if (total_steps-1) != step and step % interval != 0:
|
||||
return
|
||||
|
||||
x = model.model.process_latent_out(x)
|
||||
x = x.to(model_management.intermediate_device())
|
||||
result.append(x)
|
||||
x0 = model.model.process_latent_out(x0)
|
||||
x0 = x0.to(model_management.intermediate_device())
|
||||
result.append(x0)
|
||||
|
||||
latent_image, noise = a1111_compat.KSamplerAdvanced_inspire.sample(model, add_noise, noise_seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image, start_at_step, end_at_step,
|
||||
noise_mode, False, callback=progress_callback, scheduler_func_opt=scheduler_func_opt)
|
||||
noise_mode, False, callback=progress_callback)
|
||||
|
||||
if len(result) > 0:
|
||||
result = torch.cat(result)
|
||||
@@ -132,202 +116,12 @@ class KSamplerAdvanced_progress(a1111_compat.KSamplerAdvanced_inspire):
|
||||
return latent_image, result
|
||||
|
||||
|
||||
def exponential_interpolation(from_cfg, to_cfg, i, steps):
|
||||
if i == steps-1:
|
||||
return to_cfg
|
||||
|
||||
if from_cfg == to_cfg:
|
||||
return from_cfg
|
||||
|
||||
if from_cfg == 0:
|
||||
return to_cfg * (1 - math.exp(-5 * i / steps)) / (1 - math.exp(-5))
|
||||
elif to_cfg == 0:
|
||||
return from_cfg * (math.exp(-5 * i / steps) - math.exp(-5)) / (1 - math.exp(-5))
|
||||
else:
|
||||
log_from = math.log(from_cfg)
|
||||
log_to = math.log(to_cfg)
|
||||
log_value = log_from + (log_to - log_from) * i / steps
|
||||
return math.exp(log_value)
|
||||
|
||||
|
||||
def logarithmic_interpolation(from_cfg, to_cfg, i, steps):
|
||||
if i == 0:
|
||||
return from_cfg
|
||||
|
||||
if i == steps-1:
|
||||
return to_cfg
|
||||
|
||||
log_i = math.log(i + 1)
|
||||
log_steps = math.log(steps + 1)
|
||||
|
||||
t = log_i / log_steps
|
||||
|
||||
return from_cfg + (to_cfg - from_cfg) * t
|
||||
|
||||
|
||||
class Guider_scheduled(CFGGuider):
|
||||
def __init__(self, model_patcher, sigmas, from_cfg, to_cfg, schedule):
|
||||
super().__init__(model_patcher)
|
||||
self.default_cfg = self.cfg
|
||||
self.sigmas = sigmas
|
||||
self.cfg_sigmas = None
|
||||
self.cfg_sigmas_i = None
|
||||
self.from_cfg = from_cfg
|
||||
self.to_cfg = to_cfg
|
||||
self.schedule = schedule
|
||||
self.last_i = 0
|
||||
self.renew_cfg_sigmas()
|
||||
|
||||
def set_cfg(self, cfg):
|
||||
self.default_cfg = cfg
|
||||
self.renew_cfg_sigmas()
|
||||
|
||||
def renew_cfg_sigmas(self):
|
||||
self.cfg_sigmas = {}
|
||||
self.cfg_sigmas_i = {}
|
||||
i = 0
|
||||
steps = len(self.sigmas) - 1
|
||||
for x in self.sigmas:
|
||||
k = float(x)
|
||||
delta = self.to_cfg - self.from_cfg
|
||||
if self.schedule == 'exp':
|
||||
self.cfg_sigmas[k] = exponential_interpolation(self.from_cfg, self.to_cfg, i, steps), i
|
||||
elif self.schedule == 'log':
|
||||
self.cfg_sigmas[k] = logarithmic_interpolation(self.from_cfg, self.to_cfg, i, steps), i
|
||||
else:
|
||||
self.cfg_sigmas[k] = self.from_cfg + delta * i / steps, i
|
||||
|
||||
self.cfg_sigmas_i[i] = self.cfg_sigmas[k]
|
||||
i += 1
|
||||
|
||||
def predict_noise(self, x, timestep, model_options={}, seed=None):
|
||||
k = float(timestep[0])
|
||||
|
||||
v = self.cfg_sigmas.get(k)
|
||||
if v is None:
|
||||
# fallback
|
||||
v = self.cfg_sigmas_i[self.last_i+1]
|
||||
self.cfg_sigmas[k] = v
|
||||
|
||||
self.last_i = v[1]
|
||||
self.cfg = v[0]
|
||||
|
||||
return super().predict_noise(x, timestep, model_options, seed)
|
||||
|
||||
|
||||
class Guider_PerpNeg_scheduled(Guider_PerpNeg):
|
||||
def __init__(self, model_patcher, sigmas, from_cfg, to_cfg, schedule, neg_scale):
|
||||
super().__init__(model_patcher)
|
||||
self.default_cfg = self.cfg
|
||||
self.sigmas = sigmas
|
||||
self.cfg_sigmas = None
|
||||
self.cfg_sigmas_i = None
|
||||
self.from_cfg = from_cfg
|
||||
self.to_cfg = to_cfg
|
||||
self.schedule = schedule
|
||||
self.neg_scale = neg_scale
|
||||
self.last_i = 0
|
||||
self.renew_cfg_sigmas()
|
||||
|
||||
def set_cfg(self, cfg):
|
||||
self.default_cfg = cfg
|
||||
self.renew_cfg_sigmas()
|
||||
|
||||
def renew_cfg_sigmas(self):
|
||||
self.cfg_sigmas = {}
|
||||
self.cfg_sigmas_i = {}
|
||||
i = 0
|
||||
steps = len(self.sigmas) - 1
|
||||
for x in self.sigmas:
|
||||
k = float(x)
|
||||
delta = self.to_cfg - self.from_cfg
|
||||
if self.schedule == 'exp':
|
||||
self.cfg_sigmas[k] = exponential_interpolation(self.from_cfg, self.to_cfg, i, steps), i
|
||||
elif self.schedule == 'log':
|
||||
self.cfg_sigmas[k] = logarithmic_interpolation(self.from_cfg, self.to_cfg, i, steps), i
|
||||
else:
|
||||
self.cfg_sigmas[k] = self.from_cfg + delta * i / steps, i
|
||||
|
||||
self.cfg_sigmas_i[i] = self.cfg_sigmas[k]
|
||||
i += 1
|
||||
|
||||
def predict_noise(self, x, timestep, model_options={}, seed=None):
|
||||
k = float(timestep[0])
|
||||
|
||||
v = self.cfg_sigmas.get(k)
|
||||
if v is None:
|
||||
# fallback
|
||||
v = self.cfg_sigmas_i[self.last_i+1]
|
||||
self.cfg_sigmas[k] = v
|
||||
|
||||
self.last_i = v[1]
|
||||
self.cfg = v[0]
|
||||
|
||||
return super().predict_noise(x, timestep, model_options, seed)
|
||||
|
||||
|
||||
class ScheduledCFGGuider:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"model": ("MODEL", ),
|
||||
"positive": ("CONDITIONING", ),
|
||||
"negative": ("CONDITIONING", ),
|
||||
"sigmas": ("SIGMAS", ),
|
||||
"from_cfg": ("FLOAT", {"default": 6.5, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}),
|
||||
"to_cfg": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}),
|
||||
"schedule": (["linear", "log", "exp"], {'default': 'log'})
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("GUIDER", "SIGMAS")
|
||||
|
||||
FUNCTION = "get_guider"
|
||||
CATEGORY = "sampling/custom_sampling/guiders"
|
||||
|
||||
def get_guider(self, model, positive, negative, sigmas, from_cfg, to_cfg, schedule):
|
||||
guider = Guider_scheduled(model, sigmas, from_cfg, to_cfg, schedule)
|
||||
guider.set_conds(positive, negative)
|
||||
return guider, sigmas
|
||||
|
||||
|
||||
class ScheduledPerpNegCFGGuider:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"model": ("MODEL", ),
|
||||
"positive": ("CONDITIONING", ),
|
||||
"negative": ("CONDITIONING", ),
|
||||
"empty_conditioning": ("CONDITIONING", ),
|
||||
"neg_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}),
|
||||
"sigmas": ("SIGMAS", ),
|
||||
"from_cfg": ("FLOAT", {"default": 6.5, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}),
|
||||
"to_cfg": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1, "round": 0.01}),
|
||||
"schedule": (["linear", "log", "exp"], {'default': 'log'})
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("GUIDER", "SIGMAS")
|
||||
|
||||
FUNCTION = "get_guider"
|
||||
CATEGORY = "sampling/custom_sampling/guiders"
|
||||
|
||||
def get_guider(self, model, positive, negative, empty_conditioning, neg_scale, sigmas, from_cfg, to_cfg, schedule):
|
||||
guider = Guider_PerpNeg_scheduled(model, sigmas, from_cfg, to_cfg, schedule, neg_scale)
|
||||
guider.set_conds(positive, negative, empty_conditioning)
|
||||
return guider, sigmas
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"KSamplerProgress //Inspire": KSampler_progress,
|
||||
"KSamplerAdvancedProgress //Inspire": KSamplerAdvanced_progress,
|
||||
"ScheduledCFGGuider //Inspire": ScheduledCFGGuider,
|
||||
"ScheduledPerpNegCFGGuider //Inspire": ScheduledPerpNegCFGGuider
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"KSamplerProgress //Inspire": "KSampler Progress (Inspire)",
|
||||
"KSamplerAdvancedProgress //Inspire": "KSampler Advanced Progress (Inspire)",
|
||||
"ScheduledCFGGuider //Inspire": "Scheduled CFGGuider (Inspire)",
|
||||
"ScheduledPerpNegCFGGuider //Inspire": "Scheduled PerpNeg CFGGuider (Inspire)"
|
||||
}
|
||||
|
||||
@@ -40,9 +40,6 @@ class MediaPipeFaceMeshDetector:
|
||||
|
||||
resolution = normalize_size_base_64(image.shape[2], image.shape[1])
|
||||
facemesh_image = pre_obj().detect(image, self.max_faces, threshold, resolution=resolution)[0]
|
||||
|
||||
facemesh_image = nodes.ImageScale().upscale(facemesh_image, "bilinear", image.shape[2], image.shape[1], "disabled")[0]
|
||||
|
||||
segs = seg_obj().doit(facemesh_image, crop_factor, not self.is_segm, crop_min_size, drop_size, dilation,
|
||||
self.face, self.mouth, self.left_eyebrow, self.left_eye, self.left_pupil,
|
||||
self.right_eyebrow, self.right_eye, self.right_pupil)[0]
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import colorsys
|
||||
|
||||
|
||||
def hex_to_hsv(hex_color):
|
||||
hex_color = hex_color.lstrip('#')
|
||||
r, g, b = tuple(int(hex_color[i:i+2], 16) / 255.0 for i in (0, 2, 4))
|
||||
|
||||
h, s, v = colorsys.rgb_to_hsv(r, g, b)
|
||||
|
||||
hue = h * 360
|
||||
|
||||
saturation = s
|
||||
value = v
|
||||
|
||||
return hue, saturation, value
|
||||
|
||||
|
||||
class RGB_HexToHSV:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"rgb_hex": ("STRING", {"defaultInput": True}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("FLOAT", "FLOAT", "FLOAT")
|
||||
RETURN_NAMES = ("hue", "saturation", "value")
|
||||
FUNCTION = "doit"
|
||||
CATEGORY = "InspirePack/Util"
|
||||
|
||||
def doit(self, rgb_hex):
|
||||
return hex_to_hsv(rgb_hex)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"RGB_HexToHSV //Inspire": RGB_HexToHSV,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"RGB_HexToHSV //Inspire": "RGB Hex To HSV (Inspire)",
|
||||
}
|
||||
+1
-1
@@ -44,7 +44,7 @@ app.registerExtension({
|
||||
|
||||
Object.defineProperty(node, 'imgs', {
|
||||
set(v) {
|
||||
if (v && !v[0].complete) {
|
||||
if (!v[0].complete) {
|
||||
let orig_onload = v[0].onload;
|
||||
v[0].onload = function(v2) {
|
||||
if(orig_onload)
|
||||
|
||||
+15
-57
@@ -158,57 +158,21 @@ export function register_concat_conditionings_with_multiplier_node(nodeType, nod
|
||||
}
|
||||
|
||||
async function ensure_multipliers() {
|
||||
if(self.ensuring_multipliers) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
self.ensuring_multipliers = true;
|
||||
let ncon = get_input_count('conditioning', true);
|
||||
let nmul = get_input_count('multiplier', false) + get_widget_count('multiplier');
|
||||
|
||||
let ncon = get_input_count('conditioning', true);
|
||||
let nmul = get_input_count('multiplier', false) + get_widget_count('multiplier');
|
||||
if(ncon == 0 && nmul == 0)
|
||||
ncon = 1;
|
||||
|
||||
if(ncon == 0 && nmul == 0)
|
||||
ncon = 1;
|
||||
|
||||
for(let i = nmul+1; i<=ncon; i++) {
|
||||
let config = { min: 0, max: 10, step: 0.1, round: 0.01, precision: 2 };
|
||||
|
||||
// NOTE: addWidget trigger calling ensure_multipliers
|
||||
let widget = await self.addWidget("number", `multiplier${i}`, 1.0, function (v) {
|
||||
if (config.round) {
|
||||
self.value = Math.round(v/config.round)*config.round;
|
||||
} else {
|
||||
self.value = v;
|
||||
}
|
||||
}, config);
|
||||
}
|
||||
}
|
||||
finally{
|
||||
self.ensuring_multipliers = null;
|
||||
}
|
||||
}
|
||||
|
||||
async function recover_multipliers() {
|
||||
if(self.recover_multipliers) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
self.recover_multipliers = true;
|
||||
for(let i = 1; i<self.widgets_values.length; i++) {
|
||||
let config = { min: 0, max: 10, step: 0.1, round: 0.01, precision: 2 };
|
||||
|
||||
// NOTE: addWidget trigger calling recover_multipliers
|
||||
let widget = await self.addWidget("number", `multiplier${i+1}`, 1.0, function (v) {
|
||||
if (config.round) {
|
||||
self.value = Math.round(v/config.round)*config.round;
|
||||
} else {
|
||||
self.value = v;
|
||||
}
|
||||
}, config);
|
||||
}
|
||||
}
|
||||
finally{
|
||||
self.recover_multipliers = null;
|
||||
for(let i = nmul+1; i<=ncon; i++) {
|
||||
let config = { min: 0, max: 10, step: 0.1, round: 0.01, precision: 2 };
|
||||
let widget = await self.addWidget("number", `multiplier${i}`, 1.0, function (v) {
|
||||
if (config.round) {
|
||||
self.value = Math.round(v/config.round)*config.round;
|
||||
} else {
|
||||
self.value = v;
|
||||
}
|
||||
}, config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,18 +183,12 @@ export function register_concat_conditionings_with_multiplier_node(nodeType, nod
|
||||
}
|
||||
}
|
||||
|
||||
const stackTrace = new Error().stack;
|
||||
if(!stackTrace.includes('loadGraphData') && !stackTrace.includes('pasteFromClipboard')) {
|
||||
if(!Error().stack.includes('pasteFromClipboard')) {
|
||||
await remove_garbage();
|
||||
await ensure_inputs();
|
||||
}
|
||||
|
||||
if(!stackTrace.includes('loadGraphData')) {
|
||||
await ensure_multipliers();
|
||||
}
|
||||
else {
|
||||
await recover_multipliers();
|
||||
}
|
||||
await ensure_multipliers();
|
||||
|
||||
await this.setSize( this.computeSize() );
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
[project]
|
||||
name = "comfyui-inspire-pack"
|
||||
description = "This extension provides various nodes to support Lora Block Weight and the Impact Pack. Provides many easily applicable regional features and applications for Variation Seed."
|
||||
version = "0.82.4"
|
||||
license = "LICENSE"
|
||||
dependencies = ["matplotlib", "cachetools"]
|
||||
|
||||
[project.urls]
|
||||
Repository = "https://github.com/ltdrdata/ComfyUI-Inspire-Pack"
|
||||
# Used by Comfy Registry https://comfyregistry.org
|
||||
|
||||
[tool.comfy]
|
||||
PublisherId = "drltdata"
|
||||
DisplayName = "ComfyUI Inspire Pack"
|
||||
Icon = ""
|
||||
+1
-2
@@ -1,3 +1,2 @@
|
||||
matplotlib
|
||||
cachetools
|
||||
numpy<2
|
||||
cachetools
|
||||
Reference in New Issue
Block a user