Skip to content

Commit

Permalink
Added Derive Seed node (#1611)
Browse files Browse the repository at this point in the history
* Added Random Seed node

* Added migration

* Rebrand to Derive Seed

* Made seeds their own datatype

* Added test for migration
  • Loading branch information
RunDevelopment authored Mar 1, 2023
1 parent da6bae0 commit a001d93
Show file tree
Hide file tree
Showing 17 changed files with 950 additions and 124 deletions.
11 changes: 5 additions & 6 deletions backend/src/nodes/nodes/external_stable_diffusion/img2img.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@
BoolInput,
EnumInput,
ImageInput,
NumberInput,
SeedInput,
SliderInput,
TextAreaInput,
)
from ...properties.outputs import ImageOutput
from ...utils.seed import Seed
from ...utils.utils import get_h_w_c
from . import category as ExternalStableDiffusionCategory

Expand All @@ -52,9 +53,7 @@ def __init__(self):
controls_step=0.1,
precision=2,
),
group("seed")(
NumberInput("Seed", minimum=0, default=42, maximum=4294967296)
),
group("seed")(SeedInput()),
SliderInput("Steps", minimum=1, default=20, maximum=150),
EnumInput(
SamplerName,
Expand Down Expand Up @@ -115,7 +114,7 @@ def run(
prompt: Optional[str],
negative_prompt: Optional[str],
denoising_strength: float,
seed: int,
seed: Seed,
steps: int,
sampler_name: SamplerName,
cfg_scale: float,
Expand All @@ -132,7 +131,7 @@ def run(
"prompt": prompt or "",
"negative_prompt": negative_prompt or "",
"denoising_strength": denoising_strength,
"seed": seed,
"seed": seed.to_u32(),
"steps": steps,
"sampler_name": sampler_name.value,
"cfg_scale": cfg_scale,
Expand Down
11 changes: 5 additions & 6 deletions backend/src/nodes/nodes/external_stable_diffusion/inpainting.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@
BoolInput,
EnumInput,
ImageInput,
NumberInput,
SeedInput,
SliderInput,
TextAreaInput,
)
from ...properties.outputs import ImageOutput
from ...utils.seed import Seed
from ...utils.utils import get_h_w_c
from . import category as ExternalStableDiffusionCategory

Expand Down Expand Up @@ -64,9 +65,7 @@ def __init__(self):
controls_step=0.1,
precision=2,
),
group("seed")(
NumberInput("Seed", minimum=0, default=42, maximum=4294967296)
),
group("seed")(SeedInput()),
SliderInput("Steps", minimum=1, default=20, maximum=150),
EnumInput(
SamplerName,
Expand Down Expand Up @@ -148,7 +147,7 @@ def run(
prompt: Optional[str],
negative_prompt: Optional[str],
denoising_strength: float,
seed: int,
seed: Seed,
steps: int,
sampler_name: SamplerName,
cfg_scale: float,
Expand All @@ -174,7 +173,7 @@ def run(
"prompt": prompt or "",
"negative_prompt": negative_prompt or "",
"denoising_strength": denoising_strength,
"seed": seed,
"seed": seed.to_u32(),
"steps": steps,
"sampler_name": sampler_name.value,
"cfg_scale": cfg_scale,
Expand Down
11 changes: 5 additions & 6 deletions backend/src/nodes/nodes/external_stable_diffusion/outpainting.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@
BoolInput,
EnumInput,
ImageInput,
NumberInput,
SeedInput,
SliderInput,
TextAreaInput,
)
from ...properties.outputs import ImageOutput
from ...utils.seed import Seed
from ...utils.utils import get_h_w_c
from . import category as ExternalStableDiffusionCategory

Expand Down Expand Up @@ -61,9 +62,7 @@ def __init__(self):
controls_step=0.1,
precision=2,
),
group("seed")(
NumberInput("Seed", minimum=0, default=42, maximum=4294967296)
),
group("seed")(SeedInput()),
SliderInput("Steps", minimum=1, default=20, maximum=150),
EnumInput(
SamplerName,
Expand Down Expand Up @@ -176,7 +175,7 @@ def run(
prompt: Optional[str],
negative_prompt: Optional[str],
denoising_strength: float,
seed: int,
seed: Seed,
steps: int,
sampler_name: SamplerName,
cfg_scale: float,
Expand Down Expand Up @@ -221,7 +220,7 @@ def run(
"prompt": prompt or "",
"negative_prompt": negative_prompt or "",
"denoising_strength": denoising_strength,
"seed": seed,
"seed": seed.to_u32(),
"steps": steps,
"sampler_name": sampler_name.value,
"cfg_scale": cfg_scale,
Expand Down
11 changes: 5 additions & 6 deletions backend/src/nodes/nodes/external_stable_diffusion/txt2img.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
from ...properties.inputs import (
BoolInput,
EnumInput,
NumberInput,
SeedInput,
SliderInput,
TextAreaInput,
)
from ...properties.outputs import ImageOutput
from ...utils.seed import Seed
from ...utils.utils import get_h_w_c
from . import category as ExternalStableDiffusionCategory

Expand All @@ -38,9 +39,7 @@ def __init__(self):
self.inputs = [
TextAreaInput("Prompt").make_optional(),
TextAreaInput("Negative Prompt").make_optional(),
group("seed")(
NumberInput("Seed", minimum=0, default=42, maximum=4294967296)
),
group("seed")(SeedInput()),
SliderInput("Steps", minimum=1, default=20, maximum=150),
EnumInput(
SamplerName,
Expand Down Expand Up @@ -94,7 +93,7 @@ def run(
self,
prompt: Optional[str],
negative_prompt: Optional[str],
seed: int,
seed: Seed,
steps: int,
sampler_name: SamplerName,
cfg_scale: float,
Expand All @@ -108,7 +107,7 @@ def run(
request_data = {
"prompt": prompt or "",
"negative_prompt": negative_prompt or "",
"seed": seed,
"seed": seed.to_u32(),
"steps": steps,
"sampler_name": sampler_name.value,
"cfg_scale": cfg_scale,
Expand Down
32 changes: 18 additions & 14 deletions backend/src/nodes/nodes/image/create_noise.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,22 @@

import numpy as np

from nodes.impl.image_utils import cartesian_product
from nodes.impl.noise_functions.simplex import SimplexNoise
from nodes.impl.noise_functions.value import ValueNoise
from nodes.node_base import NodeBase, group
from nodes.node_factory import NodeFactory
from nodes.properties import expression
from nodes.properties.inputs import BoolInput, EnumInput, NumberInput, SliderInput
from nodes.properties.outputs import ImageOutput

from ...groups import conditional_group
from ...impl.image_utils import cartesian_product
from ...impl.noise_functions.simplex import SimplexNoise
from ...impl.noise_functions.value import ValueNoise
from ...node_base import NodeBase, group
from ...node_factory import NodeFactory
from ...properties import expression
from ...properties.inputs import (
BoolInput,
EnumInput,
NumberInput,
SeedInput,
SliderInput,
)
from ...properties.outputs import ImageOutput
from ...utils.seed import Seed
from . import category as ImageCategory


Expand All @@ -35,9 +41,7 @@ def __init__(self):
self.inputs = [
NumberInput("Width", minimum=1, unit="px", default=256),
NumberInput("Height", minimum=1, unit="px", default=256),
group("seed")(
NumberInput("Seed", minimum=0, maximum=2**32 - 1, default=0),
),
group("seed")(SeedInput()),
EnumInput(
NoiseMethod,
default_value=NoiseMethod.SIMPLEX,
Expand Down Expand Up @@ -129,7 +133,7 @@ def run(
self,
width: int,
height: int,
seed: int,
seed: Seed,
noise_method: NoiseMethod,
scale: float,
brightness: float,
Expand All @@ -151,7 +155,7 @@ def run(
"tile_spherical": tile_spherical,
"scale": scale,
"brightness": brightness,
"seed": seed,
"seed": seed.to_u32(),
}

generator_class = None
Expand Down
19 changes: 9 additions & 10 deletions backend/src/nodes/nodes/image_filter/add_noise.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
)
from ...node_base import NodeBase, group
from ...node_factory import NodeFactory
from ...properties.inputs import EnumInput, ImageInput, NumberInput, SliderInput
from ...properties.inputs import EnumInput, ImageInput, SeedInput, SliderInput
from ...properties.outputs import ImageOutput
from ...utils.seed import Seed
from . import category as ImageFilterCategory


Expand Down Expand Up @@ -45,9 +46,7 @@ def __init__(self):
},
),
SliderInput("Amount", minimum=0, maximum=100, default=50),
group("seed")(
NumberInput("Seed", minimum=None, maximum=None, default=0),
),
group("seed")(SeedInput()),
]
self.outputs = [
ImageOutput(
Expand All @@ -73,17 +72,17 @@ def run(
noise_type: NoiseType,
noise_color: NoiseColor,
amount: int,
seed: int,
seed: Seed,
) -> np.ndarray:
if noise_type == NoiseType.GAUSSIAN:
return gaussian_noise(img, amount / 100, noise_color, seed)
return gaussian_noise(img, amount / 100, noise_color, seed.value)
elif noise_type == NoiseType.UNIFORM:
return uniform_noise(img, amount / 100, noise_color, seed)
return uniform_noise(img, amount / 100, noise_color, seed.value)
elif noise_type == NoiseType.SALT_AND_PEPPER:
return salt_and_pepper_noise(img, amount / 100, noise_color, seed)
return salt_and_pepper_noise(img, amount / 100, noise_color, seed.value)
elif noise_type == NoiseType.POISSON:
return poisson_noise(img, amount / 100, noise_color, seed)
return poisson_noise(img, amount / 100, noise_color, seed.value)
elif noise_type == NoiseType.SPECKLE:
return speckle_noise(img, amount / 100, noise_color, seed)
return speckle_noise(img, amount / 100, noise_color, seed.value)
else:
raise ValueError(f"Unknown noise type: {noise_type}")
68 changes: 68 additions & 0 deletions backend/src/nodes/nodes/utility/derive_seed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from __future__ import annotations

import hashlib
import struct
from typing import Union

from ...node_base import NodeBase, group
from ...node_factory import NodeFactory
from ...properties.inputs import BaseInput, SeedInput
from ...properties.outputs import SeedOutput
from ...utils.seed import Seed
from ...utils.utils import ALPHABET
from . import category as UtilityCategory

Source = Union[int, float, str, Seed]


def SourceInput(label: str):
return BaseInput(
kind="generic",
label=label,
input_type="number | string | Directory | Seed",
).make_optional()


def _to_bytes(s: Source) -> bytes:
if isinstance(s, str):
return s.encode(errors="backslashreplace")
if isinstance(s, Seed):
s = s.value

i = int(s)
if isinstance(s, int) or s == i:
return i.to_bytes(i.bit_length() // 8 + 1, byteorder="big", signed=True)

return struct.pack("d", s)


@NodeFactory.register("chainner:utility:derive_seed")
class RandomNumberNode(NodeBase):
def __init__(self):
super().__init__()
self.description = "Creates a new seed from multiple sources of randomness."
self.inputs = [
group("seed")(SeedInput(has_handle=False)),
SourceInput(f"Source A"),
group("optional-list")(
*[SourceInput(f"Source {letter}") for letter in ALPHABET[1:10]],
),
]
self.outputs = [
SeedOutput(),
]

self.category = UtilityCategory
self.name = "Derive Seed"
self.icon = "MdCalculate"
self.sub = "Random"

def run(self, seed: Seed, *sources: Source | None) -> Seed:
h = hashlib.sha256()

h.update(_to_bytes(seed))
for s in sources:
if s is not None:
h.update(_to_bytes(s))

return Seed.from_bytes(h.digest())
27 changes: 6 additions & 21 deletions backend/src/nodes/nodes/utility/random_number.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
from __future__ import annotations

from random import Random
from typing import Union

from ...node_base import NodeBase, group
from ...node_factory import NodeFactory
from ...properties.inputs import BaseInput, NumberInput
from ...properties.inputs import NumberInput, SeedInput
from ...properties.outputs import NumberOutput
from ...utils.seed import Seed
from . import category as UtilityCategory


Expand All @@ -27,16 +25,7 @@ def __init__(self):
maximum=None,
default=100,
),
group("seed")(
NumberInput(
"Seed",
minimum=0,
maximum=None,
),
),
BaseInput(
input_type="uint", label="Index from Iterator", kind="generic"
).make_optional(),
group("seed")(SeedInput()),
]
self.outputs = [
NumberOutput(
Expand All @@ -47,11 +36,7 @@ def __init__(self):
self.category = UtilityCategory
self.name = "Random Number"
self.icon = "MdCalculate"
self.sub = "Math"
self.sub = "Random"

def run(
self, minval: int, maxval: int, seedval: int, frameval: Union[int, None]
) -> int:
if frameval == None:
frameval = 0
return Random((frameval + 1) * (seedval + 1)).randint(minval, maxval)
def run(self, min_val: int, max_val: int, seed: Seed) -> int:
return Random(seed.value).randint(min_val, max_val)
Loading

0 comments on commit a001d93

Please sign in to comment.