InvokeAI 2.2.4.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. backend/__init__.py +0 -0
  2. backend/invoke_ai_web_server.py +1724 -0
  3. backend/modules/__init__.py +0 -0
  4. backend/modules/create_cmd_parser.py +55 -0
  5. backend/modules/get_canvas_generation_mode.py +117 -0
  6. backend/modules/parameters.py +71 -0
  7. backend/modules/parse_seed_weights.py +47 -0
  8. configs/INITIAL_MODELS.yaml +80 -0
  9. configs/models.yaml.example +29 -0
  10. configs/sd-concepts.txt +803 -0
  11. configs/stable-diffusion/v1-finetune.yaml +110 -0
  12. configs/stable-diffusion/v1-finetune_style.yaml +103 -0
  13. configs/stable-diffusion/v1-inference.yaml +79 -0
  14. configs/stable-diffusion/v1-inpainting-inference.yaml +79 -0
  15. configs/stable-diffusion/v1-m1-finetune.yaml +110 -0
  16. docs/assets/invoke-web-server-1.png +0 -0
  17. docs/assets/invoke_ai_banner.png +0 -0
  18. invokeai-2.2.4.5.data/data/assets/caution.png +0 -0
  19. invokeai-2.2.4.5.data/data/configs/INITIAL_MODELS.yaml +80 -0
  20. invokeai-2.2.4.5.data/data/configs/models.yaml.example +29 -0
  21. invokeai-2.2.4.5.data/data/configs/sd-concepts.txt +803 -0
  22. invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-finetune.yaml +110 -0
  23. invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-finetune_style.yaml +103 -0
  24. invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-inference.yaml +79 -0
  25. invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-inpainting-inference.yaml +79 -0
  26. invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-m1-finetune.yaml +110 -0
  27. invokeai-2.2.4.5.data/data/frontend/dist/assets/Inter-Bold.790c108b.ttf +0 -0
  28. invokeai-2.2.4.5.data/data/frontend/dist/assets/Inter.b9a8e5e2.ttf +0 -0
  29. invokeai-2.2.4.5.data/data/frontend/dist/assets/favicon.0d253ced.ico +0 -0
  30. invokeai-2.2.4.5.data/data/frontend/dist/assets/index-legacy-b741077f.js +48 -0
  31. invokeai-2.2.4.5.data/data/frontend/dist/assets/index.0dadf5d0.css +1 -0
  32. invokeai-2.2.4.5.data/data/frontend/dist/assets/index.21ff81eb.js +625 -0
  33. invokeai-2.2.4.5.data/data/frontend/dist/assets/logo.13003d72.png +0 -0
  34. invokeai-2.2.4.5.data/data/frontend/dist/assets/polyfills-legacy-dde3a68a.js +4 -0
  35. invokeai-2.2.4.5.data/data/frontend/dist/assets/polyfills.1ff60148.js +1 -0
  36. invokeai-2.2.4.5.data/data/frontend/dist/index.html +23 -0
  37. invokeai-2.2.4.5.data/data/scripts/configure_invokeai.py +797 -0
  38. invokeai-2.2.4.5.data/data/scripts/create_root.py +43 -0
  39. invokeai-2.2.4.5.data/data/scripts/dream.py +10 -0
  40. invokeai-2.2.4.5.data/data/scripts/images2prompt.py +30 -0
  41. invokeai-2.2.4.5.data/data/scripts/invoke.py +5 -0
  42. invokeai-2.2.4.5.data/data/scripts/legacy_api.py +681 -0
  43. invokeai-2.2.4.5.data/data/scripts/load_models.py +12 -0
  44. invokeai-2.2.4.5.data/data/scripts/merge_embeddings.py +124 -0
  45. invokeai-2.2.4.5.data/data/scripts/preload_models.py +12 -0
  46. invokeai-2.2.4.5.data/data/scripts/sd-metadata.py +22 -0
  47. invokeai-2.2.4.5.dist-info/LICENSE +21 -0
  48. invokeai-2.2.4.5.dist-info/LICENSE-ModelWeights.txt +294 -0
  49. invokeai-2.2.4.5.dist-info/METADATA +288 -0
  50. invokeai-2.2.4.5.dist-info/RECORD +169 -0
  51. invokeai-2.2.4.5.dist-info/WHEEL +5 -0
  52. invokeai-2.2.4.5.dist-info/entry_points.txt +4 -0
  53. invokeai-2.2.4.5.dist-info/top_level.txt +6 -0
  54. invokeai-2.2.4.5.dist-info/zip-safe +1 -0
  55. ldm/__init__.py +0 -0
  56. ldm/data/__init__.py +0 -0
  57. ldm/data/base.py +31 -0
  58. ldm/data/imagenet.py +466 -0
  59. ldm/data/lsun.py +126 -0
  60. ldm/data/personalized.py +202 -0
  61. ldm/data/personalized_style.py +169 -0
  62. ldm/generate.py +1159 -0
  63. ldm/invoke/CLI.py +960 -0
  64. ldm/invoke/__init__.py +3 -0
  65. ldm/invoke/args.py +1257 -0
  66. ldm/invoke/concepts_lib.py +169 -0
  67. ldm/invoke/conditioning.py +289 -0
  68. ldm/invoke/devices.py +27 -0
  69. ldm/invoke/generator/__init__.py +4 -0
  70. ldm/invoke/generator/base.py +335 -0
  71. ldm/invoke/generator/embiggen.py +501 -0
  72. ldm/invoke/generator/img2img.py +97 -0
  73. ldm/invoke/generator/inpaint.py +358 -0
  74. ldm/invoke/generator/omnibus.py +175 -0
  75. ldm/invoke/generator/txt2img.py +88 -0
  76. ldm/invoke/generator/txt2img2img.py +182 -0
  77. ldm/invoke/globals.py +31 -0
  78. ldm/invoke/image_util.py +70 -0
  79. ldm/invoke/log.py +66 -0
  80. ldm/invoke/model_cache.py +449 -0
  81. ldm/invoke/patchmatch.py +44 -0
  82. ldm/invoke/pngwriter.py +113 -0
  83. ldm/invoke/prompt_parser.py +655 -0
  84. ldm/invoke/readline.py +442 -0
  85. ldm/invoke/restoration/__init__.py +4 -0
  86. ldm/invoke/restoration/base.py +38 -0
  87. ldm/invoke/restoration/codeformer.py +103 -0
  88. ldm/invoke/restoration/codeformer_arch.py +276 -0
  89. ldm/invoke/restoration/gfpgan.py +84 -0
  90. ldm/invoke/restoration/outcrop.py +108 -0
  91. ldm/invoke/restoration/outpaint.py +92 -0
  92. ldm/invoke/restoration/realesrgan.py +90 -0
  93. ldm/invoke/restoration/vqgan_arch.py +435 -0
  94. ldm/invoke/seamless.py +30 -0
  95. ldm/invoke/server.py +282 -0
  96. ldm/invoke/server_legacy.py +246 -0
  97. ldm/invoke/txt2mask.py +136 -0
  98. ldm/lr_scheduler.py +143 -0
  99. ldm/models/__init__.py +0 -0
  100. ldm/models/autoencoder.py +596 -0
  101. ldm/models/diffusion/__init__.py +0 -0
  102. ldm/models/diffusion/classifier.py +355 -0
  103. ldm/models/diffusion/cross_attention_control.py +443 -0
  104. ldm/models/diffusion/cross_attention_map_saving.py +95 -0
  105. ldm/models/diffusion/ddim.py +111 -0
  106. ldm/models/diffusion/ddpm.py +2263 -0
  107. ldm/models/diffusion/ksampler.py +312 -0
  108. ldm/models/diffusion/plms.py +146 -0
  109. ldm/models/diffusion/sampler.py +450 -0
  110. ldm/models/diffusion/shared_invokeai_diffusion.py +244 -0
  111. ldm/modules/__init__.py +0 -0
  112. ldm/modules/attention.py +274 -0
  113. ldm/modules/diffusionmodules/__init__.py +0 -0
  114. ldm/modules/diffusionmodules/model.py +894 -0
  115. ldm/modules/diffusionmodules/openaimodel.py +1036 -0
  116. ldm/modules/diffusionmodules/util.py +314 -0
  117. ldm/modules/distributions/__init__.py +0 -0
  118. ldm/modules/distributions/distributions.py +104 -0
  119. ldm/modules/ema.py +88 -0
  120. ldm/modules/embedding_manager.py +413 -0
  121. ldm/modules/encoders/__init__.py +0 -0
  122. ldm/modules/encoders/modules.py +772 -0
  123. ldm/modules/image_degradation/__init__.py +6 -0
  124. ldm/modules/image_degradation/bsrgan.py +846 -0
  125. ldm/modules/image_degradation/bsrgan_light.py +751 -0
  126. ldm/modules/image_degradation/utils_image.py +1024 -0
  127. ldm/modules/losses/__init__.py +1 -0
  128. ldm/modules/losses/contperceptual.py +175 -0
  129. ldm/modules/losses/vqperceptual.py +240 -0
  130. ldm/modules/x_transformer.py +752 -0
  131. ldm/simplet2i.py +13 -0
  132. ldm/util.py +264 -0
  133. scripts/configure_invokeai.py +797 -0
  134. scripts/create_root.py +43 -0
  135. scripts/dream.py +10 -0
  136. scripts/images2prompt.py +30 -0
  137. scripts/invoke.py +5 -0
  138. scripts/legacy_api.py +681 -0
  139. scripts/load_models.py +12 -0
  140. scripts/merge_embeddings.py +124 -0
  141. scripts/orig_scripts/img2img.py +296 -0
  142. scripts/orig_scripts/inpaint.py +98 -0
  143. scripts/orig_scripts/knn2img.py +397 -0
  144. scripts/orig_scripts/sample_diffusion.py +313 -0
  145. scripts/orig_scripts/train_searcher.py +147 -0
  146. scripts/orig_scripts/txt2img.py +324 -0
  147. scripts/preload_models.py +12 -0
  148. scripts/sd-metadata.py +22 -0
  149. vendored/clip/clip/__init__.py +1 -0
  150. vendored/clip/clip/bpe_simple_vocab_16e6.txt.gz +0 -0
  151. vendored/clip/clip/clip.py +237 -0
  152. vendored/clip/clip/model.py +436 -0
  153. vendored/clip/clip/simple_tokenizer.py +132 -0
  154. vendored/clip/hubconf.py +42 -0
  155. vendored/clip/setup.py +21 -0
  156. vendored/clip/tests/test_consistency.py +25 -0
  157. vendored/clipseg/datasets/coco_wrapper.py +99 -0
  158. vendored/clipseg/datasets/pascal_zeroshot.py +60 -0
  159. vendored/clipseg/datasets/pfe_dataset.py +129 -0
  160. vendored/clipseg/datasets/phrasecut.py +380 -0
  161. vendored/clipseg/datasets/utils.py +68 -0
  162. vendored/clipseg/evaluation_utils.py +292 -0
  163. vendored/clipseg/general_utils.py +272 -0
  164. vendored/clipseg/metrics.py +271 -0
  165. vendored/clipseg/models/clipseg.py +538 -0
  166. vendored/clipseg/models/vitseg.py +286 -0
  167. vendored/clipseg/score.py +453 -0
  168. vendored/clipseg/setup.py +30 -0
  169. vendored/clipseg/training.py +266 -0
ldm/invoke/args.py ADDED
@@ -0,0 +1,1257 @@
1
+ """Helper class for dealing with image generation arguments.
2
+
3
+ The Args class parses both the command line (shell) arguments, as well as the
4
+ command string passed at the invoke> prompt. It serves as the definitive repository
5
+ of all the arguments used by Generate and their default values, and implements the
6
+ preliminary metadata standards discussed here:
7
+
8
+ https://github.com/lstein/stable-diffusion/issues/266
9
+
10
+ To use:
11
+ opt = Args()
12
+
13
+ # Read in the command line options:
14
+ # this returns a namespace object like the underlying argparse library)
15
+ # You do not have to use the return value, but you can check it against None
16
+ # to detect illegal arguments on the command line.
17
+ args = opt.parse_args()
18
+ if not args:
19
+ print('oops')
20
+ sys.exit(-1)
21
+
22
+ # read in a command passed to the invoke> prompt:
23
+ opts = opt.parse_cmd('do androids dream of electric sheep? -H256 -W1024 -n4')
24
+
25
+ # The Args object acts like a namespace object
26
+ print(opt.model)
27
+
28
+ You can set attributes in the usual way, use vars(), etc.:
29
+
30
+ opt.model = 'something-else'
31
+ do_something(**vars(a))
32
+
33
+ It is helpful in saving metadata:
34
+
35
+ # To get a json representation of all the values, allowing
36
+ # you to override any values dynamically
37
+ j = opt.json(seed=42)
38
+
39
+ # To get the prompt string with the switches, allowing you
40
+ # to override any values dynamically
41
+ j = opt.dream_prompt_str(seed=42)
42
+
43
+ If you want to access the namespace objects from the shell args or the
44
+ parsed command directly, you may use the values returned from the
45
+ original calls to parse_args() and parse_cmd(), or get them later
46
+ using the _arg_switches and _cmd_switches attributes. This can be
47
+ useful if both the args and the command contain the same attribute and
48
+ you wish to apply logic as to which one to use. For example:
49
+
50
+ a = Args()
51
+ args = a.parse_args()
52
+ opts = a.parse_cmd(string)
53
+ do_grid = args.grid or opts.grid
54
+
55
+ To add new attributes, edit the _create_arg_parser() and
56
+ _create_dream_cmd_parser() methods.
57
+
58
+ **Generating and retrieving sd-metadata**
59
+
60
+ To generate a dict representing RFC266 metadata:
61
+
62
+ metadata = metadata_dumps(opt,<seeds,model_hash,postprocesser>)
63
+
64
+ This will generate an RFC266 dictionary that can then be turned into a JSON
65
+ and written to the PNG file. The optional seeds, weights, model_hash and
66
+ postprocesser arguments are not available to the opt object and so must be
67
+ provided externally. See how invoke.py does it.
68
+
69
+ Note that this function was originally called format_metadata() and a wrapper
70
+ is provided that issues a deprecation notice.
71
+
72
+ To retrieve a (series of) opt objects corresponding to the metadata, do this:
73
+
74
+ opt_list = metadata_loads(metadata)
75
+
76
+ The metadata should be pulled out of the PNG image. pngwriter has a method
77
+ retrieve_metadata that will do this, or you can do it in one swell foop
78
+ with metadata_from_png():
79
+
80
+ opt_list = metadata_from_png('/path/to/image_file.png')
81
+ """
82
+
83
+ import argparse
84
+ from argparse import Namespace, RawTextHelpFormatter
85
+ import pydoc
86
+ import json
87
+ import hashlib
88
+ import os
89
+ import re
90
+ import sys
91
+ import shlex
92
+ import copy
93
+ import base64
94
+ import functools
95
+ import warnings
96
+ import ldm.invoke
97
+ import ldm.invoke.pngwriter
98
+ from ldm.invoke.globals import Globals
99
+ from ldm.invoke.prompt_parser import split_weighted_subprompts
100
+
101
+ APP_ID = ldm.invoke.__app_id__
102
+ APP_NAME = ldm.invoke.__app_name__
103
+ APP_VERSION = ldm.invoke.__version__
104
+
105
+ SAMPLER_CHOICES = [
106
+ 'ddim',
107
+ 'k_dpm_2_a',
108
+ 'k_dpm_2',
109
+ 'k_dpmpp_2_a',
110
+ 'k_dpmpp_2',
111
+ 'k_euler_a',
112
+ 'k_euler',
113
+ 'k_heun',
114
+ 'k_lms',
115
+ 'plms',
116
+ ]
117
+
118
+ PRECISION_CHOICES = [
119
+ 'auto',
120
+ 'float32',
121
+ 'autocast',
122
+ 'float16',
123
+ ]
124
+
125
+ class ArgFormatter(argparse.RawTextHelpFormatter):
126
+ # use defined argument order to display usage
127
+ def _format_usage(self, usage, actions, groups, prefix):
128
+ if prefix is None:
129
+ prefix = 'usage: '
130
+
131
+ # if usage is specified, use that
132
+ if usage is not None:
133
+ usage = usage % dict(prog=self._prog)
134
+
135
+ # if no optionals or positionals are available, usage is just prog
136
+ elif usage is None and not actions:
137
+ usage = 'invoke>'
138
+ elif usage is None:
139
+ prog='invoke>'
140
+ # build full usage string
141
+ action_usage = self._format_actions_usage(actions, groups) # NEW
142
+ usage = ' '.join([s for s in [prog, action_usage] if s])
143
+ # omit the long line wrapping code
144
+ # prefix with 'usage:'
145
+ return '%s%s\n\n' % (prefix, usage)
146
+
147
+ class PagingArgumentParser(argparse.ArgumentParser):
148
+ '''
149
+ A custom ArgumentParser that uses pydoc to page its output.
150
+ It also supports reading defaults from an init file.
151
+ '''
152
+ def print_help(self, file=None):
153
+ text = self.format_help()
154
+ pydoc.pager(text)
155
+
156
+ def convert_arg_line_to_args(self, arg_line):
157
+ return shlex.split(arg_line,comments=True)
158
+
159
+ class Args(object):
160
+ def __init__(self,arg_parser=None,cmd_parser=None):
161
+ '''
162
+ Initialize new Args class. It takes two optional arguments, an argparse
163
+ parser for switches given on the shell command line, and an argparse
164
+ parser for switches given on the invoke> CLI line. If one or both are
165
+ missing, it creates appropriate parsers internally.
166
+ '''
167
+ self._arg_parser = arg_parser or self._create_arg_parser()
168
+ self._cmd_parser = cmd_parser or self._create_dream_cmd_parser()
169
+ self._arg_switches = self.parse_cmd('') # fill in defaults
170
+ self._cmd_switches = self.parse_cmd('') # fill in defaults
171
+
172
+ def parse_args(self):
173
+ '''Parse the shell switches and store.'''
174
+ try:
175
+ sysargs = sys.argv[1:]
176
+ # pre-parse before we do any initialization to get root directory
177
+ # and intercept --version request
178
+ switches = self._arg_parser.parse_args(sysargs)
179
+ if switches.version:
180
+ print(f'{ldm.invoke.__app_name__} {ldm.invoke.__version__}')
181
+ sys.exit(0)
182
+
183
+ print('* Initializing, be patient...')
184
+ Globals.root = os.path.abspath(switches.root_dir or Globals.root)
185
+ Globals.try_patchmatch = switches.patchmatch
186
+
187
+ # now use root directory to find the init file
188
+ initfile = os.path.expanduser(os.path.join(Globals.root,Globals.initfile))
189
+ legacyinit = os.path.expanduser('~/.invokeai')
190
+ if os.path.exists(initfile):
191
+ print(f'>> Initialization file {initfile} found. Loading...',file=sys.stderr)
192
+ sysargs.insert(0,f'@{initfile}')
193
+ elif os.path.exists(legacyinit):
194
+ print(f'>> WARNING: Old initialization file found at {legacyinit}. This location is deprecated. Please move it to {Globals.root}/invokeai.init.')
195
+ sysargs.insert(0,f'@{legacyinit}')
196
+
197
+ self._arg_switches = self._arg_parser.parse_args(sysargs)
198
+ return self._arg_switches
199
+ except Exception as e:
200
+ print(f'An exception has occurred: {e}')
201
+ return None
202
+
203
+ def parse_cmd(self,cmd_string):
204
+ '''Parse a invoke>-style command string '''
205
+ # handle the case in which the first token is a switch
206
+ if cmd_string.startswith('-'):
207
+ prompt = ''
208
+ switches = cmd_string
209
+ # handle the case in which the prompt is enclosed by quotes
210
+ elif cmd_string.startswith('"'):
211
+ a = shlex.split(cmd_string,comments=True)
212
+ prompt = a[0]
213
+ switches = shlex.join(a[1:])
214
+ else:
215
+ # no initial quote, so get everything up to the first thing
216
+ # that looks like a switch
217
+ if cmd_string.startswith('-'):
218
+ prompt = ''
219
+ switches = cmd_string
220
+ else:
221
+ match = re.match('^(.+?)\s(--?[a-zA-Z].+)',cmd_string)
222
+ if match:
223
+ prompt,switches = match.groups()
224
+ else:
225
+ prompt = cmd_string
226
+ switches = ''
227
+ try:
228
+ self._cmd_switches = self._cmd_parser.parse_args(shlex.split(switches,comments=True))
229
+ setattr(self._cmd_switches,'prompt',prompt)
230
+ return self._cmd_switches
231
+ except:
232
+ return None
233
+
234
+ def json(self,**kwargs):
235
+ return json.dumps(self.to_dict(**kwargs))
236
+
237
+ def to_dict(self,**kwargs):
238
+ a = vars(self)
239
+ a.update(kwargs)
240
+ return a
241
+
242
+ # Isn't there a more automated way of doing this?
243
+ # Ideally we get the switch strings out of the argparse objects,
244
+ # but I don't see a documented API for this.
245
+ def dream_prompt_str(self,**kwargs):
246
+ """Normalized dream_prompt."""
247
+ a = vars(self)
248
+ a.update(kwargs)
249
+ switches = list()
250
+ prompt = a['prompt']
251
+ prompt.replace('"','\\"')
252
+ switches.append(prompt)
253
+ switches.append(f'-s {a["steps"]}')
254
+ switches.append(f'-S {a["seed"]}')
255
+ switches.append(f'-W {a["width"]}')
256
+ switches.append(f'-H {a["height"]}')
257
+ switches.append(f'-C {a["cfg_scale"]}')
258
+ if a['karras_max'] is not None:
259
+ switches.append(f'--karras_max {a["karras_max"]}')
260
+ if a['perlin'] > 0:
261
+ switches.append(f'--perlin {a["perlin"]}')
262
+ if a['threshold'] > 0:
263
+ switches.append(f'--threshold {a["threshold"]}')
264
+ if a['grid']:
265
+ switches.append('--grid')
266
+ if a['seamless']:
267
+ switches.append('--seamless')
268
+ if a['hires_fix']:
269
+ switches.append('--hires_fix')
270
+
271
+ # img2img generations have parameters relevant only to them and have special handling
272
+ if a['init_img'] and len(a['init_img'])>0:
273
+ switches.append(f'-I {a["init_img"]}')
274
+ switches.append(f'-A {a["sampler_name"]}')
275
+ if a['fit']:
276
+ switches.append(f'--fit')
277
+ if a['init_mask'] and len(a['init_mask'])>0:
278
+ switches.append(f'-M {a["init_mask"]}')
279
+ if a['init_color'] and len(a['init_color'])>0:
280
+ switches.append(f'--init_color {a["init_color"]}')
281
+ if a['strength'] and a['strength']>0:
282
+ switches.append(f'-f {a["strength"]}')
283
+ if a['inpaint_replace']:
284
+ switches.append(f'--inpaint_replace')
285
+ if a['text_mask']:
286
+ switches.append(f'-tm {" ".join([str(u) for u in a["text_mask"]])}')
287
+ else:
288
+ switches.append(f'-A {a["sampler_name"]}')
289
+
290
+ # facetool-specific parameters, only print if running facetool
291
+ if a['facetool_strength']:
292
+ switches.append(f'-G {a["facetool_strength"]}')
293
+ switches.append(f'-ft {a["facetool"]}')
294
+ if a["facetool"] == "codeformer":
295
+ switches.append(f'-cf {a["codeformer_fidelity"]}')
296
+
297
+ if a['outcrop']:
298
+ switches.append(f'-c {" ".join([str(u) for u in a["outcrop"]])}')
299
+
300
+ # esrgan-specific parameters
301
+ if a['upscale']:
302
+ switches.append(f'-U {" ".join([str(u) for u in a["upscale"]])}')
303
+
304
+ # embiggen parameters
305
+ if a['embiggen']:
306
+ switches.append(f'--embiggen {" ".join([str(u) for u in a["embiggen"]])}')
307
+ if a['embiggen_tiles']:
308
+ switches.append(f'--embiggen_tiles {" ".join([str(u) for u in a["embiggen_tiles"]])}')
309
+ if a['embiggen_strength']:
310
+ switches.append(f'--embiggen_strength {a["embiggen_strength"]}')
311
+
312
+ # outpainting parameters
313
+ if a['out_direction']:
314
+ switches.append(f'-D {" ".join([str(u) for u in a["out_direction"]])}')
315
+
316
+ # LS: slight semantic drift which needs addressing in the future:
317
+ # 1. Variations come out of the stored metadata as a packed string with the keyword "variations"
318
+ # 2. However, they come out of the CLI (and probably web) with the keyword "with_variations" and
319
+ # in broken-out form. Variation (1) should be changed to comply with (2)
320
+ if a['with_variations'] and len(a['with_variations'])>0:
321
+ formatted_variations = ','.join(f'{seed}:{weight}' for seed, weight in (a["with_variations"]))
322
+ switches.append(f'-V {formatted_variations}')
323
+ if 'variations' in a and len(a['variations'])>0:
324
+ switches.append(f'-V {a["variations"]}')
325
+ return ' '.join(switches)
326
+
327
+ def __getattribute__(self,name):
328
+ '''
329
+ Returns union of command-line arguments and dream_prompt arguments,
330
+ with the latter superseding the former.
331
+ '''
332
+ cmd_switches = None
333
+ arg_switches = None
334
+ try:
335
+ cmd_switches = object.__getattribute__(self,'_cmd_switches')
336
+ arg_switches = object.__getattribute__(self,'_arg_switches')
337
+ except AttributeError:
338
+ pass
339
+
340
+ if cmd_switches and arg_switches and name=='__dict__':
341
+ return self._merge_dict(
342
+ arg_switches.__dict__,
343
+ cmd_switches.__dict__,
344
+ )
345
+ try:
346
+ return object.__getattribute__(self,name)
347
+ except AttributeError:
348
+ pass
349
+
350
+ if not hasattr(cmd_switches,name) and not hasattr(arg_switches,name):
351
+ raise AttributeError
352
+
353
+ value_arg,value_cmd = (None,None)
354
+ try:
355
+ value_cmd = getattr(cmd_switches,name)
356
+ except AttributeError:
357
+ pass
358
+ try:
359
+ value_arg = getattr(arg_switches,name)
360
+ except AttributeError:
361
+ pass
362
+
363
+ # here is where we can pick and choose which to use
364
+ # default behavior is to choose the dream_command value over
365
+ # the arg value. For example, the --grid and --individual options are a little
366
+ # funny because of their push/pull relationship. This is how to handle it.
367
+ if name=='grid':
368
+ if cmd_switches.individual:
369
+ return False
370
+ else:
371
+ return value_cmd or value_arg
372
+ return value_cmd if value_cmd is not None else value_arg
373
+
374
+ def __setattr__(self,name,value):
375
+ if name.startswith('_'):
376
+ object.__setattr__(self,name,value)
377
+ else:
378
+ self._cmd_switches.__dict__[name] = value
379
+
380
+ def _merge_dict(self,dict1,dict2):
381
+ new_dict = {}
382
+ for k in set(list(dict1.keys())+list(dict2.keys())):
383
+ value1 = dict1.get(k,None)
384
+ value2 = dict2.get(k,None)
385
+ new_dict[k] = value2 if value2 is not None else value1
386
+ return new_dict
387
+
388
+ def _create_init_file(self,initfile:str):
389
+ with open(initfile, mode='w', encoding='utf-8') as f:
390
+ f.write('''# InvokeAI initialization file
391
+ # Put frequently-used startup commands here, one or more per line
392
+ # Examples:
393
+ # --web --host=0.0.0.0
394
+ # --steps 20
395
+ # -Ak_euler_a -C10.0
396
+ '''
397
+ )
398
+
399
+ def _create_arg_parser(self):
400
+ '''
401
+ This defines all the arguments used on the command line when you launch
402
+ the CLI or web backend.
403
+ '''
404
+ parser = PagingArgumentParser(
405
+ description=
406
+ """
407
+ Generate images using Stable Diffusion.
408
+ Use --web to launch the web interface.
409
+ Use --from_file to load prompts from a file path or standard input ("-").
410
+ Otherwise you will be dropped into an interactive command prompt (type -h for help.)
411
+ Other command-line arguments are defaults that can usually be overridden
412
+ prompt the command prompt.
413
+ """,
414
+ fromfile_prefix_chars='@',
415
+ )
416
+ general_group = parser.add_argument_group('General')
417
+ model_group = parser.add_argument_group('Model selection')
418
+ file_group = parser.add_argument_group('Input/output')
419
+ web_server_group = parser.add_argument_group('Web server')
420
+ render_group = parser.add_argument_group('Rendering')
421
+ postprocessing_group = parser.add_argument_group('Postprocessing')
422
+ deprecated_group = parser.add_argument_group('Deprecated options')
423
+
424
+ deprecated_group.add_argument('--laion400m')
425
+ deprecated_group.add_argument('--weights') # deprecated
426
+ general_group.add_argument(
427
+ '--version','-V',
428
+ action='store_true',
429
+ help='Print InvokeAI version number'
430
+ )
431
+ model_group.add_argument(
432
+ '--root_dir',
433
+ default=None,
434
+ help='Path to directory containing "models", "outputs" and "configs". If not present will read from environment variable INVOKEAI_ROOT. Defaults to ~/invokeai.',
435
+ )
436
+ model_group.add_argument(
437
+ '--config',
438
+ '-c',
439
+ '-config',
440
+ dest='conf',
441
+ default='./configs/models.yaml',
442
+ help='Path to configuration file for alternate models.',
443
+ )
444
+ model_group.add_argument(
445
+ '--model',
446
+ help='Indicates which diffusion model to load (defaults to "default" stanza in configs/models.yaml)',
447
+ )
448
+ model_group.add_argument(
449
+ '--weight_dirs',
450
+ nargs='+',
451
+ type=str,
452
+ help='List of one or more directories that will be auto-scanned for new model weights to import',
453
+ )
454
+ model_group.add_argument(
455
+ '--png_compression','-z',
456
+ type=int,
457
+ default=6,
458
+ choices=range(0,9),
459
+ dest='png_compression',
460
+ help='level of PNG compression, from 0 (none) to 9 (maximum). Default is 6.'
461
+ )
462
+ model_group.add_argument(
463
+ '-F',
464
+ '--full_precision',
465
+ dest='full_precision',
466
+ action='store_true',
467
+ help='Deprecated way to set --precision=float32',
468
+ )
469
+ model_group.add_argument(
470
+ '--max_loaded_models',
471
+ dest='max_loaded_models',
472
+ type=int,
473
+ default=2,
474
+ help='Maximum number of models to keep in memory for fast switching, including the one in GPU',
475
+ )
476
+ model_group.add_argument(
477
+ '--free_gpu_mem',
478
+ dest='free_gpu_mem',
479
+ action='store_true',
480
+ help='Force free gpu memory before final decoding',
481
+ )
482
+ model_group.add_argument(
483
+ '--precision',
484
+ dest='precision',
485
+ type=str,
486
+ choices=PRECISION_CHOICES,
487
+ metavar='PRECISION',
488
+ help=f'Set model precision. Defaults to auto selected based on device. Options: {", ".join(PRECISION_CHOICES)}',
489
+ default='auto',
490
+ )
491
+ model_group.add_argument(
492
+ '--nsfw_checker'
493
+ '--safety_checker',
494
+ action=argparse.BooleanOptionalAction,
495
+ dest='safety_checker',
496
+ default=False,
497
+ help='Check for and blur potentially NSFW images. Use --no-nsfw_checker to disable.',
498
+ )
499
+ model_group.add_argument(
500
+ '--patchmatch',
501
+ action=argparse.BooleanOptionalAction,
502
+ default=True,
503
+ help='Load the patchmatch extension for outpainting. Use --no-patchmatch to disable.',
504
+ )
505
+ file_group.add_argument(
506
+ '--from_file',
507
+ dest='infile',
508
+ type=str,
509
+ help='If specified, load prompts from this file',
510
+ )
511
+ file_group.add_argument(
512
+ '--outdir',
513
+ '-o',
514
+ type=str,
515
+ help='Directory to save generated images and a log of prompts and seeds. Default: outputs/img-samples',
516
+ default='outputs/img-samples',
517
+ )
518
+ file_group.add_argument(
519
+ '--prompt_as_dir',
520
+ '-p',
521
+ action='store_true',
522
+ help='Place images in subdirectories named after the prompt.',
523
+ )
524
+ render_group.add_argument(
525
+ '--fnformat',
526
+ default='{prefix}.{seed}.png',
527
+ type=str,
528
+ help='Overwrite the filename format. You can use any argument as wildcard enclosed in curly braces. Default is {prefix}.{seed}.png',
529
+ )
530
+ render_group.add_argument(
531
+ '-s',
532
+ '--steps',
533
+ type=int,
534
+ default=50,
535
+ help='Number of steps'
536
+ )
537
+ render_group.add_argument(
538
+ '-W',
539
+ '--width',
540
+ type=int,
541
+ help='Image width, multiple of 64',
542
+ )
543
+ render_group.add_argument(
544
+ '-H',
545
+ '--height',
546
+ type=int,
547
+ help='Image height, multiple of 64',
548
+ )
549
+ render_group.add_argument(
550
+ '-C',
551
+ '--cfg_scale',
552
+ default=7.5,
553
+ type=float,
554
+ help='Classifier free guidance (CFG) scale - higher numbers cause generator to "try" harder.',
555
+ )
556
+ render_group.add_argument(
557
+ '--sampler',
558
+ '-A',
559
+ '-m',
560
+ dest='sampler_name',
561
+ type=str,
562
+ choices=SAMPLER_CHOICES,
563
+ metavar='SAMPLER_NAME',
564
+ help=f'Set the default sampler. Supported samplers: {", ".join(SAMPLER_CHOICES)}',
565
+ default='k_lms',
566
+ )
567
+ render_group.add_argument(
568
+ '-f',
569
+ '--strength',
570
+ type=float,
571
+ help='img2img strength for noising/unnoising. 0.0 preserves image exactly, 1.0 replaces it completely',
572
+ )
573
+ render_group.add_argument(
574
+ '-T',
575
+ '-fit',
576
+ '--fit',
577
+ action=argparse.BooleanOptionalAction,
578
+ help='If specified, will resize the input image to fit within the dimensions of width x height (512x512 default)',
579
+ )
580
+
581
+ render_group.add_argument(
582
+ '--grid',
583
+ '-g',
584
+ action=argparse.BooleanOptionalAction,
585
+ help='generate a grid'
586
+ )
587
+ render_group.add_argument(
588
+ '--embedding_directory',
589
+ '--embedding_path',
590
+ dest='embedding_path',
591
+ default='embeddings',
592
+ type=str,
593
+ help='Path to a directory containing .bin and/or .pt files, or a single .bin/.pt file. You may use subdirectories. (default is ROOTDIR/embeddings)'
594
+ )
595
+ render_group.add_argument(
596
+ '--embeddings',
597
+ action=argparse.BooleanOptionalAction,
598
+ default=True,
599
+ help='Enable embedding directory (default). Use --no-embeddings to disable.',
600
+ )
601
+ render_group.add_argument(
602
+ '--enable_image_debugging',
603
+ action='store_true',
604
+ help='Generates debugging image to display'
605
+ )
606
+ render_group.add_argument(
607
+ '--karras_max',
608
+ type=int,
609
+ default=None,
610
+ help="control the point at which the K* samplers will shift from using the Karras noise schedule (good for low step counts) to the LatentDiffusion noise schedule (good for high step counts). Set to 0 to use LatentDiffusion for all step values, and to a high value (e.g. 1000) to use Karras for all step values. [29]."
611
+ )
612
+ # Restoration related args
613
+ postprocessing_group.add_argument(
614
+ '--no_restore',
615
+ dest='restore',
616
+ action='store_false',
617
+ help='Disable face restoration with GFPGAN or codeformer',
618
+ )
619
+ postprocessing_group.add_argument(
620
+ '--no_upscale',
621
+ dest='esrgan',
622
+ action='store_false',
623
+ help='Disable upscaling with ESRGAN',
624
+ )
625
+ postprocessing_group.add_argument(
626
+ '--esrgan_bg_tile',
627
+ type=int,
628
+ default=400,
629
+ help='Tile size for background sampler, 0 for no tile during testing. Default: 400.',
630
+ )
631
+ postprocessing_group.add_argument(
632
+ '--gfpgan_model_path',
633
+ type=str,
634
+ default='./models/gfpgan/GFPGANv1.4.pth',
635
+ help='Indicates the path to the GFPGAN model',
636
+ )
637
+ web_server_group.add_argument(
638
+ '--web',
639
+ dest='web',
640
+ action='store_true',
641
+ help='Start in web server mode.',
642
+ )
643
+ web_server_group.add_argument(
644
+ '--web_develop',
645
+ dest='web_develop',
646
+ action='store_true',
647
+ help='Start in web server development mode.',
648
+ )
649
+ web_server_group.add_argument(
650
+ "--web_verbose",
651
+ action="store_true",
652
+ help="Enables verbose logging",
653
+ )
654
+ web_server_group.add_argument(
655
+ "--cors",
656
+ nargs="*",
657
+ type=str,
658
+ help="Additional allowed origins, comma-separated",
659
+ )
660
+ web_server_group.add_argument(
661
+ '--host',
662
+ type=str,
663
+ default='127.0.0.1',
664
+ help='Web server: Host or IP to listen on. Set to 0.0.0.0 to accept traffic from other devices on your network.'
665
+ )
666
+ web_server_group.add_argument(
667
+ '--port',
668
+ type=int,
669
+ default='9090',
670
+ help='Web server: Port to listen on'
671
+ )
672
+ web_server_group.add_argument(
673
+ '--certfile',
674
+ type=str,
675
+ default=None,
676
+ help='Web server: Path to certificate file to use for SSL. Use together with --keyfile'
677
+ )
678
+ web_server_group.add_argument(
679
+ '--keyfile',
680
+ type=str,
681
+ default=None,
682
+ help='Web server: Path to private key file to use for SSL. Use together with --certfile'
683
+ )
684
+ web_server_group.add_argument(
685
+ '--gui',
686
+ dest='gui',
687
+ action='store_true',
688
+ help='Start InvokeAI GUI',
689
+ )
690
+ return parser
691
+
692
+ # This creates the parser that processes commands on the invoke> command line
693
+ def _create_dream_cmd_parser(self):
694
+ parser = PagingArgumentParser(
695
+ formatter_class=ArgFormatter,
696
+ description=
697
+ """
698
+ *Image generation*
699
+ invoke> a fantastic alien landscape -W576 -H512 -s60 -n4
700
+
701
+ *postprocessing*
702
+ !fix applies upscaling/facefixing to a previously-generated image.
703
+ invoke> !fix 0000045.4829112.png -G1 -U4 -ft codeformer
704
+
705
+ *History manipulation*
706
+ !fetch retrieves the command used to generate an earlier image. Provide
707
+ a directory wildcard and the name of a file to write and all the commands
708
+ used to generate the images in the directory will be written to that file.
709
+ invoke> !fetch 0000015.8929913.png
710
+ invoke> a fantastic alien landscape -W 576 -H 512 -s 60 -A plms -C 7.5
711
+ invoke> !fetch /path/to/images/*.png prompts.txt
712
+
713
+ !replay /path/to/prompts.txt
714
+ Replays all the prompts contained in the file prompts.txt.
715
+
716
+ !history lists all the commands issued during the current session.
717
+
718
+ !NN retrieves the NNth command from the history
719
+
720
+ *Model manipulation*
721
+ !models -- list models in configs/models.yaml
722
+ !switch <model_name> -- switch to model named <model_name>
723
+ !import_model path/to/weights/file.ckpt -- adds a model to your config
724
+ !edit_model <model_name> -- edit a model's description
725
+ !del_model <model_name> -- delete a model
726
+ """
727
+ )
728
+ render_group = parser.add_argument_group('General rendering')
729
+ img2img_group = parser.add_argument_group('Image-to-image and inpainting')
730
+ inpainting_group = parser.add_argument_group('Inpainting')
731
+ outpainting_group = parser.add_argument_group('Outpainting and outcropping')
732
+ variation_group = parser.add_argument_group('Creating and combining variations')
733
+ postprocessing_group = parser.add_argument_group('Post-processing')
734
+ special_effects_group = parser.add_argument_group('Special effects')
735
+ deprecated_group = parser.add_argument_group('Deprecated options')
736
+ render_group.add_argument(
737
+ '--prompt',
738
+ default='',
739
+ help='prompt string',
740
+ )
741
+ render_group.add_argument(
742
+ '-s',
743
+ '--steps',
744
+ type=int,
745
+ help='Number of steps'
746
+ )
747
+ render_group.add_argument(
748
+ '-S',
749
+ '--seed',
750
+ type=int,
751
+ default=None,
752
+ help='Image seed; a +ve integer, or use -1 for the previous seed, -2 for the one before that, etc',
753
+ )
754
+ render_group.add_argument(
755
+ '-n',
756
+ '--iterations',
757
+ type=int,
758
+ default=1,
759
+ help='Number of samplings to perform (slower, but will provide seeds for individual images)',
760
+ )
761
+ render_group.add_argument(
762
+ '-W',
763
+ '--width',
764
+ type=int,
765
+ help='Image width, multiple of 64',
766
+ )
767
+ render_group.add_argument(
768
+ '-H',
769
+ '--height',
770
+ type=int,
771
+ help='Image height, multiple of 64',
772
+ )
773
+ render_group.add_argument(
774
+ '-C',
775
+ '--cfg_scale',
776
+ type=float,
777
+ help='Classifier free guidance (CFG) scale - higher numbers cause generator to "try" harder.',
778
+ )
779
+ render_group.add_argument(
780
+ '--threshold',
781
+ default=0.0,
782
+ type=float,
783
+ help='Latent threshold for classifier free guidance (CFG) - prevent generator from "trying" too hard. Use positive values, 0 disables.',
784
+ )
785
+ render_group.add_argument(
786
+ '--perlin',
787
+ default=0.0,
788
+ type=float,
789
+ help='Perlin noise scale (0.0 - 1.0) - add perlin noise to the initialization instead of the usual gaussian noise.',
790
+ )
791
+ render_group.add_argument(
792
+ '--fnformat',
793
+ default='{prefix}.{seed}.png',
794
+ type=str,
795
+ help='Overwrite the filename format. You can use any argument as wildcard enclosed in curly braces. Default is {prefix}.{seed}.png',
796
+ )
797
+ render_group.add_argument(
798
+ '--grid',
799
+ '-g',
800
+ action=argparse.BooleanOptionalAction,
801
+ help='generate a grid'
802
+ )
803
+ render_group.add_argument(
804
+ '-i',
805
+ '--individual',
806
+ action='store_true',
807
+ help='override command-line --grid setting and generate individual images'
808
+ )
809
+ render_group.add_argument(
810
+ '-x',
811
+ '--skip_normalize',
812
+ action='store_true',
813
+ help='Skip subprompt weight normalization',
814
+ )
815
+ render_group.add_argument(
816
+ '-A',
817
+ '-m',
818
+ '--sampler',
819
+ dest='sampler_name',
820
+ type=str,
821
+ choices=SAMPLER_CHOICES,
822
+ metavar='SAMPLER_NAME',
823
+ help=f'Switch to a different sampler. Supported samplers: {", ".join(SAMPLER_CHOICES)}',
824
+ )
825
+ render_group.add_argument(
826
+ '-t',
827
+ '--log_tokenization',
828
+ action='store_true',
829
+ help='shows how the prompt is split into tokens'
830
+ )
831
+ render_group.add_argument(
832
+ '--outdir',
833
+ '-o',
834
+ type=str,
835
+ help='Directory to save generated images and a log of prompts and seeds',
836
+ )
837
+ render_group.add_argument(
838
+ '--hires_fix',
839
+ action='store_true',
840
+ dest='hires_fix',
841
+ help='Create hires image using img2img to prevent duplicated objects'
842
+ )
843
+ render_group.add_argument(
844
+ '--save_intermediates',
845
+ type=int,
846
+ default=0,
847
+ dest='save_intermediates',
848
+ help='Save every nth intermediate image into an "intermediates" directory within the output directory'
849
+ )
850
+ render_group.add_argument(
851
+ '--png_compression','-z',
852
+ type=int,
853
+ default=6,
854
+ choices=range(0,10),
855
+ dest='png_compression',
856
+ help='level of PNG compression, from 0 (none) to 9 (maximum). [6]'
857
+ )
858
+ render_group.add_argument(
859
+ '--karras_max',
860
+ type=int,
861
+ default=None,
862
+ help="control the point at which the K* samplers will shift from using the Karras noise schedule (good for low step counts) to the LatentDiffusion noise schedule (good for high step counts). Set to 0 to use LatentDiffusion for all step values, and to a high value (e.g. 1000) to use Karras for all step values. [29]."
863
+ )
864
+ img2img_group.add_argument(
865
+ '-I',
866
+ '--init_img',
867
+ type=str,
868
+ help='Path to input image for img2img mode (supersedes width and height)',
869
+ )
870
+ img2img_group.add_argument(
871
+ '-tm',
872
+ '--text_mask',
873
+ nargs='+',
874
+ type=str,
875
+ help='Use the clipseg classifier to generate the mask area for inpainting. Provide a description of the area to mask ("a mug"), optionally followed by the confidence level threshold (0-1.0; defaults to 0.5).',
876
+ default=None,
877
+ )
878
+ img2img_group.add_argument(
879
+ '--init_color',
880
+ type=str,
881
+ help='Path to reference image for color correction (used for repeated img2img and inpainting)'
882
+ )
883
+ img2img_group.add_argument(
884
+ '-T',
885
+ '-fit',
886
+ '--fit',
887
+ action='store_true',
888
+ help='If specified, will resize the input image to fit within the dimensions of width x height (512x512 default)',
889
+ )
890
+ img2img_group.add_argument(
891
+ '-f',
892
+ '--strength',
893
+ type=float,
894
+ help='img2img strength for noising/unnoising. 0.0 preserves image exactly, 1.0 replaces it completely',
895
+ )
896
+ inpainting_group.add_argument(
897
+ '-M',
898
+ '--init_mask',
899
+ type=str,
900
+ help='Path to input mask for inpainting mode (supersedes width and height)',
901
+ )
902
+ inpainting_group.add_argument(
903
+ '--invert_mask',
904
+ action='store_true',
905
+ help='Invert the mask',
906
+ )
907
+ inpainting_group.add_argument(
908
+ '-r',
909
+ '--inpaint_replace',
910
+ type=float,
911
+ default=0.0,
912
+ help='when inpainting, adjust how aggressively to replace the part of the picture under the mask, from 0.0 (a gentle merge) to 1.0 (replace entirely)',
913
+ )
914
+ outpainting_group.add_argument(
915
+ '-c',
916
+ '--outcrop',
917
+ nargs='+',
918
+ type=str,
919
+ metavar=('direction','pixels'),
920
+ help='Outcrop the image with one or more direction/pixel pairs: e.g. -c top 64 bottom 128 left 64 right 64',
921
+ )
922
+ outpainting_group.add_argument(
923
+ '--force_outpaint',
924
+ action='store_true',
925
+ default=False,
926
+ help='Force outpainting if you have no inpainting mask to pass',
927
+ )
928
+ outpainting_group.add_argument(
929
+ '--seam_size',
930
+ type=int,
931
+ default=0,
932
+ help='When outpainting, size of the mask around the seam between original and outpainted image',
933
+ )
934
+ outpainting_group.add_argument(
935
+ '--seam_blur',
936
+ type=int,
937
+ default=0,
938
+ help='When outpainting, the amount to blur the seam inwards',
939
+ )
940
+ outpainting_group.add_argument(
941
+ '--seam_strength',
942
+ type=float,
943
+ default=0.7,
944
+ help='When outpainting, the img2img strength to use when filling the seam. Values around 0.7 work well',
945
+ )
946
+ outpainting_group.add_argument(
947
+ '--seam_steps',
948
+ type=int,
949
+ default=10,
950
+ help='When outpainting, the number of steps to use to fill the seam. Low values (~10) work well',
951
+ )
952
+ outpainting_group.add_argument(
953
+ '--tile_size',
954
+ type=int,
955
+ default=32,
956
+ help='When outpainting, the tile size to use for filling outpaint areas',
957
+ )
958
+ postprocessing_group.add_argument(
959
+ '--new_prompt',
960
+ type=str,
961
+ help='Change the text prompt applied during postprocessing (default, use original generation prompt)',
962
+ )
963
+ postprocessing_group.add_argument(
964
+ '-ft',
965
+ '--facetool',
966
+ type=str,
967
+ default='gfpgan',
968
+ help='Select the face restoration AI to use: gfpgan, codeformer',
969
+ )
970
+ postprocessing_group.add_argument(
971
+ '-G',
972
+ '--facetool_strength',
973
+ '--gfpgan_strength',
974
+ type=float,
975
+ help='The strength at which to apply the face restoration to the result.',
976
+ default=0.0,
977
+ )
978
+ postprocessing_group.add_argument(
979
+ '-cf',
980
+ '--codeformer_fidelity',
981
+ type=float,
982
+ help='Used along with CodeFormer. Takes values between 0 and 1. 0 produces high quality but low accuracy. 1 produces high accuracy but low quality.',
983
+ default=0.75
984
+ )
985
+ postprocessing_group.add_argument(
986
+ '-U',
987
+ '--upscale',
988
+ nargs='+',
989
+ type=float,
990
+ help='Scale factor (1, 2, 3, 4, etc..) for upscaling final output followed by upscaling strength (0-1.0). If strength not specified, defaults to 0.75',
991
+ default=None,
992
+ )
993
+ postprocessing_group.add_argument(
994
+ '--save_original',
995
+ '-save_orig',
996
+ action='store_true',
997
+ help='Save original. Use it when upscaling to save both versions.',
998
+ )
999
+ postprocessing_group.add_argument(
1000
+ '--embiggen',
1001
+ '-embiggen',
1002
+ nargs='+',
1003
+ type=float,
1004
+ help='Arbitrary upscaling using img2img. Provide scale factor (0.75), optionally followed by strength (0.75) and tile overlap proportion (0.25).',
1005
+ default=None,
1006
+ )
1007
+ postprocessing_group.add_argument(
1008
+ '--embiggen_tiles',
1009
+ '-embiggen_tiles',
1010
+ nargs='+',
1011
+ type=int,
1012
+ help='For embiggen, provide list of tiles to process and replace onto the image e.g. `1 3 5`.',
1013
+ default=None,
1014
+ )
1015
+ postprocessing_group.add_argument(
1016
+ '--embiggen_strength',
1017
+ '-embiggen_strength',
1018
+ type=float,
1019
+ help='The strength of the embiggen img2img step, defaults to 0.4',
1020
+ default=None,
1021
+ )
1022
+ special_effects_group.add_argument(
1023
+ '--seamless',
1024
+ action='store_true',
1025
+ help='Change the model to seamless tiling (circular) mode',
1026
+ )
1027
+ special_effects_group.add_argument(
1028
+ '--seamless_axes',
1029
+ default=['x', 'y'],
1030
+ type=list[str],
1031
+ help='Specify which axes to use circular convolution on.',
1032
+ )
1033
+ variation_group.add_argument(
1034
+ '-v',
1035
+ '--variation_amount',
1036
+ default=0.0,
1037
+ type=float,
1038
+ help='If > 0, generates variations on the initial seed instead of random seeds per iteration. Must be between 0 and 1. Higher values will be more different.'
1039
+ )
1040
+ variation_group.add_argument(
1041
+ '-V',
1042
+ '--with_variations',
1043
+ default=None,
1044
+ type=str,
1045
+ help='list of variations to apply, in the format `seed:weight,seed:weight,...'
1046
+ )
1047
+ render_group.add_argument(
1048
+ '--use_mps_noise',
1049
+ action='store_true',
1050
+ dest='use_mps_noise',
1051
+ help='Simulate noise on M1 systems to get the same results'
1052
+ )
1053
+ deprecated_group.add_argument(
1054
+ '-D',
1055
+ '--out_direction',
1056
+ nargs='+',
1057
+ type=str,
1058
+ metavar=('direction', 'pixels'),
1059
+ help='Older outcropping system. Direction to extend the given image (left|right|top|bottom). If a distance pixel value is not specified it defaults to half the image size'
1060
+ )
1061
+ return parser
1062
+
1063
+ def format_metadata(**kwargs):
1064
+ print(f'format_metadata() is deprecated. Please use metadata_dumps()')
1065
+ return metadata_dumps(kwargs)
1066
+
1067
+ def metadata_dumps(opt,
1068
+ seeds=[],
1069
+ model_hash=None,
1070
+ postprocessing=None):
1071
+ '''
1072
+ Given an Args object, returns a dict containing the keys and
1073
+ structure of the proposed stable diffusion metadata standard
1074
+ https://github.com/lstein/stable-diffusion/discussions/392
1075
+ This is intended to be turned into JSON and stored in the
1076
+ "sd
1077
+ '''
1078
+
1079
+ # top-level metadata minus `image` or `images`
1080
+ metadata = {
1081
+ 'model' : 'stable diffusion',
1082
+ 'model_id' : opt.model,
1083
+ 'model_hash' : model_hash,
1084
+ 'app_id' : ldm.invoke.__app_id__,
1085
+ 'app_version' : ldm.invoke.__version__,
1086
+ }
1087
+
1088
+ # # add some RFC266 fields that are generated internally, and not as
1089
+ # # user args
1090
+ image_dict = opt.to_dict(
1091
+ postprocessing=postprocessing
1092
+ )
1093
+
1094
+ # remove any image keys not mentioned in RFC #266
1095
+ rfc266_img_fields = ['type','postprocessing','sampler','prompt','seed','variations','steps',
1096
+ 'cfg_scale','threshold','perlin','step_number','width','height','extra','strength','seamless'
1097
+ 'init_img','init_mask','facetool','facetool_strength','upscale']
1098
+ rfc_dict ={}
1099
+
1100
+ for item in image_dict.items():
1101
+ key,value = item
1102
+ if key in rfc266_img_fields:
1103
+ rfc_dict[key] = value
1104
+
1105
+ # semantic drift
1106
+ rfc_dict['sampler'] = image_dict.get('sampler_name',None)
1107
+
1108
+ # display weighted subprompts (liable to change)
1109
+ if opt.prompt:
1110
+ subprompts = split_weighted_subprompts(opt.prompt)
1111
+ subprompts = [{'prompt':x[0],'weight':x[1]} for x in subprompts]
1112
+ rfc_dict['prompt'] = subprompts
1113
+
1114
+ # 'variations' should always exist and be an array, empty or consisting of {'seed': seed, 'weight': weight} pairs
1115
+ rfc_dict['variations'] = [{'seed':x[0],'weight':x[1]} for x in opt.with_variations] if opt.with_variations else []
1116
+
1117
+ # if variations are present then we need to replace 'seed' with 'orig_seed'
1118
+ if hasattr(opt,'first_seed'):
1119
+ rfc_dict['seed'] = opt.first_seed
1120
+
1121
+ if opt.init_img:
1122
+ rfc_dict['type'] = 'img2img'
1123
+ rfc_dict['strength_steps'] = rfc_dict.pop('strength')
1124
+ rfc_dict['orig_hash'] = calculate_init_img_hash(opt.init_img)
1125
+ rfc_dict['inpaint_replace'] = opt.inpaint_replace
1126
+ else:
1127
+ rfc_dict['type'] = 'txt2img'
1128
+ rfc_dict.pop('strength')
1129
+
1130
+ if len(seeds)==0 and opt.seed:
1131
+ seeds=[seed]
1132
+
1133
+ if opt.grid:
1134
+ images = []
1135
+ for seed in seeds:
1136
+ rfc_dict['seed'] = seed
1137
+ images.append(copy.copy(rfc_dict))
1138
+ metadata['images'] = images
1139
+ else:
1140
+ # there should only ever be a single seed if we did not generate a grid
1141
+ assert len(seeds) == 1, 'Expected a single seed'
1142
+ rfc_dict['seed'] = seeds[0]
1143
+ metadata['image'] = rfc_dict
1144
+
1145
+ return metadata
1146
+
1147
+ @functools.lru_cache(maxsize=50)
1148
+ def args_from_png(png_file_path) -> list[Args]:
1149
+ '''
1150
+ Given the path to a PNG file created by invoke.py,
1151
+ retrieves a list of Args objects containing the image
1152
+ data.
1153
+ '''
1154
+ try:
1155
+ meta = ldm.invoke.pngwriter.retrieve_metadata(png_file_path)
1156
+ except AttributeError:
1157
+ return [legacy_metadata_load({},png_file_path)]
1158
+
1159
+ try:
1160
+ return metadata_loads(meta)
1161
+ except:
1162
+ return [legacy_metadata_load(meta,png_file_path)]
1163
+
1164
+ @functools.lru_cache(maxsize=50)
1165
+ def metadata_from_png(png_file_path) -> Args:
1166
+ '''
1167
+ Given the path to a PNG file created by dream.py, retrieves
1168
+ an Args object containing the image metadata. Note that this
1169
+ returns a single Args object, not multiple.
1170
+ '''
1171
+ args_list = args_from_png(png_file_path)
1172
+ return args_list[0] if len(args_list)>0 else Args() # empty args
1173
+
1174
+ def dream_cmd_from_png(png_file_path):
1175
+ opt = metadata_from_png(png_file_path)
1176
+ return opt.dream_prompt_str()
1177
+
1178
+ def metadata_loads(metadata) -> list:
1179
+ '''
1180
+ Takes the dictionary corresponding to RFC266 (https://github.com/lstein/stable-diffusion/issues/266)
1181
+ and returns a series of opt objects for each of the images described in the dictionary. Note that this
1182
+ returns a list, and not a single object. See metadata_from_png() for a more convenient function for
1183
+ files that contain a single image.
1184
+ '''
1185
+ results = []
1186
+ try:
1187
+ if 'images' in metadata['sd-metadata']:
1188
+ images = metadata['sd-metadata']['images']
1189
+ else:
1190
+ images = [metadata['sd-metadata']['image']]
1191
+ for image in images:
1192
+ # repack the prompt and variations
1193
+ if 'prompt' in image:
1194
+ image['prompt'] = repack_prompt(image['prompt'])
1195
+ if 'variations' in image:
1196
+ image['variations'] = ','.join([':'.join([str(x['seed']),str(x['weight'])]) for x in image['variations']])
1197
+ # fix a bit of semantic drift here
1198
+ image['sampler_name']=image.pop('sampler')
1199
+ opt = Args()
1200
+ opt._cmd_switches = Namespace(**image)
1201
+ results.append(opt)
1202
+ except Exception as e:
1203
+ import sys, traceback
1204
+ print('>> could not read metadata',file=sys.stderr)
1205
+ print(traceback.format_exc(), file=sys.stderr)
1206
+ return results
1207
+
1208
+ def repack_prompt(prompt_list:list)->str:
1209
+ # in the common case of no weighting syntax, just return the prompt as is
1210
+ if len(prompt_list) > 1:
1211
+ return ','.join([':'.join([x['prompt'], str(x['weight'])]) for x in prompt_list])
1212
+ else:
1213
+ return prompt_list[0]['prompt']
1214
+
1215
+ # image can either be a file path on disk or a base64-encoded
1216
+ # representation of the file's contents
1217
+ def calculate_init_img_hash(image_string):
1218
+ prefix = 'data:image/png;base64,'
1219
+ hash = None
1220
+ if image_string.startswith(prefix):
1221
+ imagebase64 = image_string[len(prefix):]
1222
+ imagedata = base64.b64decode(imagebase64)
1223
+ with open('outputs/test.png','wb') as file:
1224
+ file.write(imagedata)
1225
+ sha = hashlib.sha256()
1226
+ sha.update(imagedata)
1227
+ hash = sha.hexdigest()
1228
+ else:
1229
+ hash = sha256(image_string)
1230
+ return hash
1231
+
1232
+ # Bah. This should be moved somewhere else...
1233
+ def sha256(path):
1234
+ sha = hashlib.sha256()
1235
+ with open(path,'rb') as f:
1236
+ while True:
1237
+ data = f.read(65536)
1238
+ if not data:
1239
+ break
1240
+ sha.update(data)
1241
+ return sha.hexdigest()
1242
+
1243
+ def legacy_metadata_load(meta,pathname) -> Args:
1244
+ opt = Args()
1245
+ if 'Dream' in meta and len(meta['Dream']) > 0:
1246
+ dream_prompt = meta['Dream']
1247
+ opt.parse_cmd(dream_prompt)
1248
+ else: # if nothing else, we can get the seed
1249
+ match = re.search('\d+\.(\d+)',pathname)
1250
+ if match:
1251
+ seed = match.groups()[0]
1252
+ opt.seed = seed
1253
+ else:
1254
+ opt.prompt = ''
1255
+ opt.seed = 0
1256
+ return opt
1257
+