File size: 4,911 Bytes
4450790
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
"""See node."""
import random
from datetime import datetime

from .constants import get_category, get_name
from .log import log_node_warn, log_node_info

# Some extension must be setting a seed as server-generated seeds were not random. We'll set a new
# seed and use that state going forward.
initial_random_state = random.getstate()
random.seed(datetime.now().timestamp())
rgthree_seed_random_state = random.getstate()
random.setstate(initial_random_state)


def new_random_seed():
  """ Gets a new random seed from the rgthree_seed_random_state and resetting the previous state."""
  global rgthree_seed_random_state
  prev_random_state = random.getstate()
  random.setstate(rgthree_seed_random_state)
  seed = random.randint(1, 1125899906842624)
  rgthree_seed_random_state = random.getstate()
  random.setstate(prev_random_state)
  return seed


class RgthreeSeed:
  """Seed node."""

  NAME = get_name('Seed')
  CATEGORY = get_category()

  @classmethod
  def INPUT_TYPES(cls):  # pylint: disable = invalid-name, missing-function-docstring
    return {
      "required": {
        "seed": ("INT", {
          "default": 0,
          "min": -1125899906842624,
          "max": 1125899906842624
        }),
      },
      "hidden": {
        "prompt": "PROMPT",
        "extra_pnginfo": "EXTRA_PNGINFO",
        "unique_id": "UNIQUE_ID",
      },
    }

  RETURN_TYPES = ("INT",)
  RETURN_NAMES = ("SEED",)
  FUNCTION = "main"

  @classmethod
  def IS_CHANGED(cls, seed, prompt=None, extra_pnginfo=None, unique_id=None):
    """Forces a changed state if we happen to get a special seed, as if from the API directly."""
    if seed in (-1, -2, -3):
      # This isn't used, but a different value than previous will force it to be "changed"
      return new_random_seed()
    return seed

  def main(self, seed=0, prompt=None, extra_pnginfo=None, unique_id=None):
    """Returns the passed seed on execution."""

    # We generate random seeds on the frontend in the seed node before sending the workflow in for
    # many reasons. However, if we want to use this in an API call without changing the seed before
    # sending, then users _could_ pass in "-1" and get a random seed used and added to the metadata.
    # Though, this should likely be discouraged for several reasons (thus, a lot of logging).
    if seed in (-1, -2, -3):
      log_node_warn(self.NAME,
                    f'Got "{seed}" as passed seed. ' +
                    'This shouldn\'t happen when queueing from the ComfyUI frontend.',
                    msg_color="YELLOW")
      if seed in (-2, -3):
        log_node_warn(self.NAME,
                      f'Cannot {"increment" if seed == -2 else "decrement"} seed from ' +
                      'server, but will generate a new random seed.',
                      msg_color="YELLOW")

      original_seed = seed
      seed = new_random_seed()
      log_node_info(self.NAME, f'Server-generated random seed {seed} and saving to workflow.')
      log_node_warn(
        self.NAME,
        'NOTE: Re-queues passing in "{seed}" and server-generated random seed won\'t be cached.',
        msg_color="YELLOW")

      if unique_id is None:
        log_node_warn(
          self.NAME, 'Cannot save server-generated seed to image metadata because ' +
          'the node\'s id was not provided.')
      else:
        if extra_pnginfo is None:
          log_node_warn(
            self.NAME, 'Cannot save server-generated seed to image workflow ' +
            'metadata because workflow was not provided.')
        else:
          workflow_node = next(
            (x for x in extra_pnginfo['workflow']['nodes'] if x['id'] == int(unique_id)), None)
          if workflow_node is None or 'widgets_values' not in workflow_node:
            log_node_warn(
              self.NAME, 'Cannot save server-generated seed to image workflow ' +
              'metadata because node was not found in the provided workflow.')
          else:
            for index, widget_value in enumerate(workflow_node['widgets_values']):
              if widget_value == original_seed:
                workflow_node['widgets_values'][index] = seed

        if prompt is None:
          log_node_warn(
            self.NAME, 'Cannot save server-generated seed to image API prompt ' +
            'metadata because prompt was not provided.')
        else:
          prompt_node = prompt[str(unique_id)]
          if prompt_node is None or 'inputs' not in prompt_node or 'seed' not in prompt_node[
              'inputs']:
            log_node_warn(
              self.NAME, 'Cannot save server-generated seed to image workflow ' +
              'metadata because node was not found in the provided workflow.')
          else:
            prompt_node['inputs']['seed'] = seed

    return (seed,)