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.
- backend/__init__.py +0 -0
- backend/invoke_ai_web_server.py +1724 -0
- backend/modules/__init__.py +0 -0
- backend/modules/create_cmd_parser.py +55 -0
- backend/modules/get_canvas_generation_mode.py +117 -0
- backend/modules/parameters.py +71 -0
- backend/modules/parse_seed_weights.py +47 -0
- configs/INITIAL_MODELS.yaml +80 -0
- configs/models.yaml.example +29 -0
- configs/sd-concepts.txt +803 -0
- configs/stable-diffusion/v1-finetune.yaml +110 -0
- configs/stable-diffusion/v1-finetune_style.yaml +103 -0
- configs/stable-diffusion/v1-inference.yaml +79 -0
- configs/stable-diffusion/v1-inpainting-inference.yaml +79 -0
- configs/stable-diffusion/v1-m1-finetune.yaml +110 -0
- docs/assets/invoke-web-server-1.png +0 -0
- docs/assets/invoke_ai_banner.png +0 -0
- invokeai-2.2.4.5.data/data/assets/caution.png +0 -0
- invokeai-2.2.4.5.data/data/configs/INITIAL_MODELS.yaml +80 -0
- invokeai-2.2.4.5.data/data/configs/models.yaml.example +29 -0
- invokeai-2.2.4.5.data/data/configs/sd-concepts.txt +803 -0
- invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-finetune.yaml +110 -0
- invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-finetune_style.yaml +103 -0
- invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-inference.yaml +79 -0
- invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-inpainting-inference.yaml +79 -0
- invokeai-2.2.4.5.data/data/configs/stable-diffusion/v1-m1-finetune.yaml +110 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/Inter-Bold.790c108b.ttf +0 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/Inter.b9a8e5e2.ttf +0 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/favicon.0d253ced.ico +0 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/index-legacy-b741077f.js +48 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/index.0dadf5d0.css +1 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/index.21ff81eb.js +625 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/logo.13003d72.png +0 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/polyfills-legacy-dde3a68a.js +4 -0
- invokeai-2.2.4.5.data/data/frontend/dist/assets/polyfills.1ff60148.js +1 -0
- invokeai-2.2.4.5.data/data/frontend/dist/index.html +23 -0
- invokeai-2.2.4.5.data/data/scripts/configure_invokeai.py +797 -0
- invokeai-2.2.4.5.data/data/scripts/create_root.py +43 -0
- invokeai-2.2.4.5.data/data/scripts/dream.py +10 -0
- invokeai-2.2.4.5.data/data/scripts/images2prompt.py +30 -0
- invokeai-2.2.4.5.data/data/scripts/invoke.py +5 -0
- invokeai-2.2.4.5.data/data/scripts/legacy_api.py +681 -0
- invokeai-2.2.4.5.data/data/scripts/load_models.py +12 -0
- invokeai-2.2.4.5.data/data/scripts/merge_embeddings.py +124 -0
- invokeai-2.2.4.5.data/data/scripts/preload_models.py +12 -0
- invokeai-2.2.4.5.data/data/scripts/sd-metadata.py +22 -0
- invokeai-2.2.4.5.dist-info/LICENSE +21 -0
- invokeai-2.2.4.5.dist-info/LICENSE-ModelWeights.txt +294 -0
- invokeai-2.2.4.5.dist-info/METADATA +288 -0
- invokeai-2.2.4.5.dist-info/RECORD +169 -0
- invokeai-2.2.4.5.dist-info/WHEEL +5 -0
- invokeai-2.2.4.5.dist-info/entry_points.txt +4 -0
- invokeai-2.2.4.5.dist-info/top_level.txt +6 -0
- invokeai-2.2.4.5.dist-info/zip-safe +1 -0
- ldm/__init__.py +0 -0
- ldm/data/__init__.py +0 -0
- ldm/data/base.py +31 -0
- ldm/data/imagenet.py +466 -0
- ldm/data/lsun.py +126 -0
- ldm/data/personalized.py +202 -0
- ldm/data/personalized_style.py +169 -0
- ldm/generate.py +1159 -0
- ldm/invoke/CLI.py +960 -0
- ldm/invoke/__init__.py +3 -0
- ldm/invoke/args.py +1257 -0
- ldm/invoke/concepts_lib.py +169 -0
- ldm/invoke/conditioning.py +289 -0
- ldm/invoke/devices.py +27 -0
- ldm/invoke/generator/__init__.py +4 -0
- ldm/invoke/generator/base.py +335 -0
- ldm/invoke/generator/embiggen.py +501 -0
- ldm/invoke/generator/img2img.py +97 -0
- ldm/invoke/generator/inpaint.py +358 -0
- ldm/invoke/generator/omnibus.py +175 -0
- ldm/invoke/generator/txt2img.py +88 -0
- ldm/invoke/generator/txt2img2img.py +182 -0
- ldm/invoke/globals.py +31 -0
- ldm/invoke/image_util.py +70 -0
- ldm/invoke/log.py +66 -0
- ldm/invoke/model_cache.py +449 -0
- ldm/invoke/patchmatch.py +44 -0
- ldm/invoke/pngwriter.py +113 -0
- ldm/invoke/prompt_parser.py +655 -0
- ldm/invoke/readline.py +442 -0
- ldm/invoke/restoration/__init__.py +4 -0
- ldm/invoke/restoration/base.py +38 -0
- ldm/invoke/restoration/codeformer.py +103 -0
- ldm/invoke/restoration/codeformer_arch.py +276 -0
- ldm/invoke/restoration/gfpgan.py +84 -0
- ldm/invoke/restoration/outcrop.py +108 -0
- ldm/invoke/restoration/outpaint.py +92 -0
- ldm/invoke/restoration/realesrgan.py +90 -0
- ldm/invoke/restoration/vqgan_arch.py +435 -0
- ldm/invoke/seamless.py +30 -0
- ldm/invoke/server.py +282 -0
- ldm/invoke/server_legacy.py +246 -0
- ldm/invoke/txt2mask.py +136 -0
- ldm/lr_scheduler.py +143 -0
- ldm/models/__init__.py +0 -0
- ldm/models/autoencoder.py +596 -0
- ldm/models/diffusion/__init__.py +0 -0
- ldm/models/diffusion/classifier.py +355 -0
- ldm/models/diffusion/cross_attention_control.py +443 -0
- ldm/models/diffusion/cross_attention_map_saving.py +95 -0
- ldm/models/diffusion/ddim.py +111 -0
- ldm/models/diffusion/ddpm.py +2263 -0
- ldm/models/diffusion/ksampler.py +312 -0
- ldm/models/diffusion/plms.py +146 -0
- ldm/models/diffusion/sampler.py +450 -0
- ldm/models/diffusion/shared_invokeai_diffusion.py +244 -0
- ldm/modules/__init__.py +0 -0
- ldm/modules/attention.py +274 -0
- ldm/modules/diffusionmodules/__init__.py +0 -0
- ldm/modules/diffusionmodules/model.py +894 -0
- ldm/modules/diffusionmodules/openaimodel.py +1036 -0
- ldm/modules/diffusionmodules/util.py +314 -0
- ldm/modules/distributions/__init__.py +0 -0
- ldm/modules/distributions/distributions.py +104 -0
- ldm/modules/ema.py +88 -0
- ldm/modules/embedding_manager.py +413 -0
- ldm/modules/encoders/__init__.py +0 -0
- ldm/modules/encoders/modules.py +772 -0
- ldm/modules/image_degradation/__init__.py +6 -0
- ldm/modules/image_degradation/bsrgan.py +846 -0
- ldm/modules/image_degradation/bsrgan_light.py +751 -0
- ldm/modules/image_degradation/utils_image.py +1024 -0
- ldm/modules/losses/__init__.py +1 -0
- ldm/modules/losses/contperceptual.py +175 -0
- ldm/modules/losses/vqperceptual.py +240 -0
- ldm/modules/x_transformer.py +752 -0
- ldm/simplet2i.py +13 -0
- ldm/util.py +264 -0
- scripts/configure_invokeai.py +797 -0
- scripts/create_root.py +43 -0
- scripts/dream.py +10 -0
- scripts/images2prompt.py +30 -0
- scripts/invoke.py +5 -0
- scripts/legacy_api.py +681 -0
- scripts/load_models.py +12 -0
- scripts/merge_embeddings.py +124 -0
- scripts/orig_scripts/img2img.py +296 -0
- scripts/orig_scripts/inpaint.py +98 -0
- scripts/orig_scripts/knn2img.py +397 -0
- scripts/orig_scripts/sample_diffusion.py +313 -0
- scripts/orig_scripts/train_searcher.py +147 -0
- scripts/orig_scripts/txt2img.py +324 -0
- scripts/preload_models.py +12 -0
- scripts/sd-metadata.py +22 -0
- vendored/clip/clip/__init__.py +1 -0
- vendored/clip/clip/bpe_simple_vocab_16e6.txt.gz +0 -0
- vendored/clip/clip/clip.py +237 -0
- vendored/clip/clip/model.py +436 -0
- vendored/clip/clip/simple_tokenizer.py +132 -0
- vendored/clip/hubconf.py +42 -0
- vendored/clip/setup.py +21 -0
- vendored/clip/tests/test_consistency.py +25 -0
- vendored/clipseg/datasets/coco_wrapper.py +99 -0
- vendored/clipseg/datasets/pascal_zeroshot.py +60 -0
- vendored/clipseg/datasets/pfe_dataset.py +129 -0
- vendored/clipseg/datasets/phrasecut.py +380 -0
- vendored/clipseg/datasets/utils.py +68 -0
- vendored/clipseg/evaluation_utils.py +292 -0
- vendored/clipseg/general_utils.py +272 -0
- vendored/clipseg/metrics.py +271 -0
- vendored/clipseg/models/clipseg.py +538 -0
- vendored/clipseg/models/vitseg.py +286 -0
- vendored/clipseg/score.py +453 -0
- vendored/clipseg/setup.py +30 -0
- vendored/clipseg/training.py +266 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
'''
|
|
2
|
+
ldm.invoke.generator.txt2img inherits from ldm.invoke.generator
|
|
3
|
+
'''
|
|
4
|
+
|
|
5
|
+
import torch
|
|
6
|
+
import numpy as np
|
|
7
|
+
import math
|
|
8
|
+
import gc
|
|
9
|
+
from ldm.invoke.generator.base import Generator
|
|
10
|
+
from ldm.models.diffusion.ddim import DDIMSampler
|
|
11
|
+
from ldm.invoke.generator.omnibus import Omnibus
|
|
12
|
+
from ldm.models.diffusion.shared_invokeai_diffusion import InvokeAIDiffuserComponent
|
|
13
|
+
from PIL import Image
|
|
14
|
+
|
|
15
|
+
class Txt2Img2Img(Generator):
|
|
16
|
+
def __init__(self, model, precision):
|
|
17
|
+
super().__init__(model, precision)
|
|
18
|
+
self.init_latent = None # for get_noise()
|
|
19
|
+
|
|
20
|
+
@torch.no_grad()
|
|
21
|
+
def get_make_image(self,prompt,sampler,steps,cfg_scale,ddim_eta,
|
|
22
|
+
conditioning,width,height,strength,step_callback=None,**kwargs):
|
|
23
|
+
"""
|
|
24
|
+
Returns a function returning an image derived from the prompt and the initial image
|
|
25
|
+
Return value depends on the seed at the time you call it
|
|
26
|
+
kwargs are 'width' and 'height'
|
|
27
|
+
"""
|
|
28
|
+
uc, c, extra_conditioning_info = conditioning
|
|
29
|
+
scale_dim = min(width, height)
|
|
30
|
+
scale = 512 / scale_dim
|
|
31
|
+
|
|
32
|
+
init_width = math.ceil(scale * width / 64) * 64
|
|
33
|
+
init_height = math.ceil(scale * height / 64) * 64
|
|
34
|
+
|
|
35
|
+
@torch.no_grad()
|
|
36
|
+
def make_image(x_T):
|
|
37
|
+
|
|
38
|
+
shape = [
|
|
39
|
+
self.latent_channels,
|
|
40
|
+
init_height // self.downsampling_factor,
|
|
41
|
+
init_width // self.downsampling_factor,
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
sampler.make_schedule(
|
|
45
|
+
ddim_num_steps=steps, ddim_eta=ddim_eta, verbose=False
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
#x = self.get_noise(init_width, init_height)
|
|
49
|
+
x = x_T
|
|
50
|
+
|
|
51
|
+
if self.free_gpu_mem and self.model.model.device != self.model.device:
|
|
52
|
+
self.model.model.to(self.model.device)
|
|
53
|
+
|
|
54
|
+
samples, _ = sampler.sample(
|
|
55
|
+
batch_size = 1,
|
|
56
|
+
S = steps,
|
|
57
|
+
x_T = x,
|
|
58
|
+
conditioning = c,
|
|
59
|
+
shape = shape,
|
|
60
|
+
verbose = False,
|
|
61
|
+
unconditional_guidance_scale = cfg_scale,
|
|
62
|
+
unconditional_conditioning = uc,
|
|
63
|
+
eta = ddim_eta,
|
|
64
|
+
img_callback = step_callback,
|
|
65
|
+
extra_conditioning_info = extra_conditioning_info
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
print(
|
|
69
|
+
f"\n>> Interpolating from {init_width}x{init_height} to {width}x{height} using DDIM sampling"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# resizing
|
|
73
|
+
samples = torch.nn.functional.interpolate(
|
|
74
|
+
samples,
|
|
75
|
+
size=(height // self.downsampling_factor, width // self.downsampling_factor),
|
|
76
|
+
mode="bilinear"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
t_enc = int(strength * steps)
|
|
80
|
+
ddim_sampler = DDIMSampler(self.model, device=self.model.device)
|
|
81
|
+
ddim_sampler.make_schedule(
|
|
82
|
+
ddim_num_steps=steps, ddim_eta=ddim_eta, verbose=False
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
z_enc = ddim_sampler.stochastic_encode(
|
|
86
|
+
samples,
|
|
87
|
+
torch.tensor([t_enc-1]).to(self.model.device),
|
|
88
|
+
noise=self.get_noise(width,height,False)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# decode it
|
|
92
|
+
samples = ddim_sampler.decode(
|
|
93
|
+
z_enc,
|
|
94
|
+
c,
|
|
95
|
+
t_enc,
|
|
96
|
+
img_callback = step_callback,
|
|
97
|
+
unconditional_guidance_scale=cfg_scale,
|
|
98
|
+
unconditional_conditioning=uc,
|
|
99
|
+
extra_conditioning_info=extra_conditioning_info,
|
|
100
|
+
all_timesteps_count=steps
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
if self.free_gpu_mem:
|
|
104
|
+
self.model.model.to('cpu')
|
|
105
|
+
self.model.cond_stage_model.device = 'cpu'
|
|
106
|
+
self.model.cond_stage_model.to('cpu')
|
|
107
|
+
gc.collect()
|
|
108
|
+
torch.cuda.empty_cache()
|
|
109
|
+
|
|
110
|
+
return self.sample_to_image(samples)
|
|
111
|
+
|
|
112
|
+
# in the case of the inpainting model being loaded, the trick of
|
|
113
|
+
# providing an interpolated latent doesn't work, so we transiently
|
|
114
|
+
# create a 512x512 PIL image, upscale it, and run the inpainting
|
|
115
|
+
# over it in img2img mode. Because the inpaing model is so conservative
|
|
116
|
+
# it doesn't change the image (much)
|
|
117
|
+
def inpaint_make_image(x_T):
|
|
118
|
+
omnibus = Omnibus(self.model,self.precision)
|
|
119
|
+
result = omnibus.generate(
|
|
120
|
+
prompt,
|
|
121
|
+
sampler=sampler,
|
|
122
|
+
width=init_width,
|
|
123
|
+
height=init_height,
|
|
124
|
+
step_callback=step_callback,
|
|
125
|
+
steps = steps,
|
|
126
|
+
cfg_scale = cfg_scale,
|
|
127
|
+
ddim_eta = ddim_eta,
|
|
128
|
+
conditioning = conditioning,
|
|
129
|
+
**kwargs
|
|
130
|
+
)
|
|
131
|
+
assert result is not None and len(result)>0,'** txt2img failed **'
|
|
132
|
+
image = result[0][0]
|
|
133
|
+
interpolated_image = image.resize((width,height),resample=Image.Resampling.LANCZOS)
|
|
134
|
+
print(kwargs.pop('init_image',None))
|
|
135
|
+
result = omnibus.generate(
|
|
136
|
+
prompt,
|
|
137
|
+
sampler=sampler,
|
|
138
|
+
init_image=interpolated_image,
|
|
139
|
+
width=width,
|
|
140
|
+
height=height,
|
|
141
|
+
seed=result[0][1],
|
|
142
|
+
step_callback=step_callback,
|
|
143
|
+
steps = steps,
|
|
144
|
+
cfg_scale = cfg_scale,
|
|
145
|
+
ddim_eta = ddim_eta,
|
|
146
|
+
conditioning = conditioning,
|
|
147
|
+
**kwargs
|
|
148
|
+
)
|
|
149
|
+
return result[0][0]
|
|
150
|
+
|
|
151
|
+
if sampler.uses_inpainting_model():
|
|
152
|
+
return inpaint_make_image
|
|
153
|
+
else:
|
|
154
|
+
return make_image
|
|
155
|
+
|
|
156
|
+
# returns a tensor filled with random numbers from a normal distribution
|
|
157
|
+
def get_noise(self,width,height,scale = True):
|
|
158
|
+
# print(f"Get noise: {width}x{height}")
|
|
159
|
+
if scale:
|
|
160
|
+
trained_square = 512 * 512
|
|
161
|
+
actual_square = width * height
|
|
162
|
+
scale = math.sqrt(trained_square / actual_square)
|
|
163
|
+
scaled_width = math.ceil(scale * width / 64) * 64
|
|
164
|
+
scaled_height = math.ceil(scale * height / 64) * 64
|
|
165
|
+
else:
|
|
166
|
+
scaled_width = width
|
|
167
|
+
scaled_height = height
|
|
168
|
+
|
|
169
|
+
device = self.model.device
|
|
170
|
+
if self.use_mps_noise or device.type == 'mps':
|
|
171
|
+
return torch.randn([1,
|
|
172
|
+
self.latent_channels,
|
|
173
|
+
scaled_height // self.downsampling_factor,
|
|
174
|
+
scaled_width // self.downsampling_factor],
|
|
175
|
+
device='cpu').to(device)
|
|
176
|
+
else:
|
|
177
|
+
return torch.randn([1,
|
|
178
|
+
self.latent_channels,
|
|
179
|
+
scaled_height // self.downsampling_factor,
|
|
180
|
+
scaled_width // self.downsampling_factor],
|
|
181
|
+
device=device)
|
|
182
|
+
|
ldm/invoke/globals.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'''
|
|
2
|
+
ldm.invoke.globals defines a small number of global variables that would
|
|
3
|
+
otherwise have to be passed through long and complex call chains.
|
|
4
|
+
|
|
5
|
+
It defines a Namespace object named "Globals" that contains
|
|
6
|
+
the attributes:
|
|
7
|
+
|
|
8
|
+
- root - the root directory under which "models" and "outputs" can be found
|
|
9
|
+
- initfile - path to the initialization file
|
|
10
|
+
- try_patchmatch - option to globally disable loading of 'patchmatch' module
|
|
11
|
+
'''
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import os.path as osp
|
|
15
|
+
from argparse import Namespace
|
|
16
|
+
|
|
17
|
+
Globals = Namespace()
|
|
18
|
+
|
|
19
|
+
# This is usually overwritten by the command line and/or environment variables
|
|
20
|
+
if os.environ.get('INVOKEAI_ROOT'):
|
|
21
|
+
Globals.root = osp.abspath(os.environ.get('INVOKEAI_ROOT'))
|
|
22
|
+
elif os.environ.get('VIRTUAL_ENV'):
|
|
23
|
+
Globals.root = osp.abspath(osp.join(os.environ.get('VIRTUAL_ENV'), '..'))
|
|
24
|
+
else:
|
|
25
|
+
Globals.root = osp.abspath(osp.expanduser('~/invokeai'))
|
|
26
|
+
|
|
27
|
+
# Where to look for the initialization file
|
|
28
|
+
Globals.initfile = 'invokeai.init'
|
|
29
|
+
|
|
30
|
+
# Try loading patchmatch
|
|
31
|
+
Globals.try_patchmatch = True
|
ldm/invoke/image_util.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from math import sqrt, floor, ceil
|
|
2
|
+
from PIL import Image
|
|
3
|
+
|
|
4
|
+
class InitImageResizer():
|
|
5
|
+
"""Simple class to create resized copies of an Image while preserving the aspect ratio."""
|
|
6
|
+
def __init__(self,Image):
|
|
7
|
+
self.image = Image
|
|
8
|
+
|
|
9
|
+
def resize(self,width=None,height=None) -> Image:
|
|
10
|
+
"""
|
|
11
|
+
Return a copy of the image resized to fit within
|
|
12
|
+
a box width x height. The aspect ratio is
|
|
13
|
+
maintained. If neither width nor height are provided,
|
|
14
|
+
then returns a copy of the original image. If one or the other is
|
|
15
|
+
provided, then the other will be calculated from the
|
|
16
|
+
aspect ratio.
|
|
17
|
+
|
|
18
|
+
Everything is floored to the nearest multiple of 64 so
|
|
19
|
+
that it can be passed to img2img()
|
|
20
|
+
"""
|
|
21
|
+
im = self.image
|
|
22
|
+
|
|
23
|
+
ar = im.width/float(im.height)
|
|
24
|
+
|
|
25
|
+
# Infer missing values from aspect ratio
|
|
26
|
+
if not(width or height): # both missing
|
|
27
|
+
width = im.width
|
|
28
|
+
height = im.height
|
|
29
|
+
elif not height: # height missing
|
|
30
|
+
height = int(width/ar)
|
|
31
|
+
elif not width: # width missing
|
|
32
|
+
width = int(height*ar)
|
|
33
|
+
|
|
34
|
+
w_scale = width/im.width
|
|
35
|
+
h_scale = height/im.height
|
|
36
|
+
scale = min(w_scale,h_scale)
|
|
37
|
+
(rw,rh) = (int(scale*im.width),int(scale*im.height))
|
|
38
|
+
|
|
39
|
+
#round everything to multiples of 64
|
|
40
|
+
width,height,rw,rh = map(
|
|
41
|
+
lambda x: x-x%64, (width,height,rw,rh)
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# no resize necessary, but return a copy
|
|
45
|
+
if im.width == width and im.height == height:
|
|
46
|
+
return im.copy()
|
|
47
|
+
|
|
48
|
+
# otherwise resize the original image so that it fits inside the bounding box
|
|
49
|
+
resized_image = self.image.resize((rw,rh),resample=Image.Resampling.LANCZOS)
|
|
50
|
+
return resized_image
|
|
51
|
+
|
|
52
|
+
def make_grid(image_list, rows=None, cols=None):
|
|
53
|
+
image_cnt = len(image_list)
|
|
54
|
+
if None in (rows, cols):
|
|
55
|
+
rows = floor(sqrt(image_cnt)) # try to make it square
|
|
56
|
+
cols = ceil(image_cnt / rows)
|
|
57
|
+
width = image_list[0].width
|
|
58
|
+
height = image_list[0].height
|
|
59
|
+
|
|
60
|
+
grid_img = Image.new('RGB', (width * cols, height * rows))
|
|
61
|
+
i = 0
|
|
62
|
+
for r in range(0, rows):
|
|
63
|
+
for c in range(0, cols):
|
|
64
|
+
if i >= len(image_list):
|
|
65
|
+
break
|
|
66
|
+
grid_img.paste(image_list[i], (c * width, r * height))
|
|
67
|
+
i = i + 1
|
|
68
|
+
|
|
69
|
+
return grid_img
|
|
70
|
+
|
ldm/invoke/log.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Functions for better format logging
|
|
3
|
+
write_log -- logs the name of the output image, prompt, and prompt args to the terminal and different types of file
|
|
4
|
+
1 write_log_message -- Writes a message to the console
|
|
5
|
+
2 write_log_files -- Writes a message to files
|
|
6
|
+
2.1 write_log_default -- File in plain text
|
|
7
|
+
2.2 write_log_txt -- File in txt format
|
|
8
|
+
2.3 write_log_markdown -- File in markdown format
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def write_log(results, log_path, file_types, output_cntr):
|
|
15
|
+
"""
|
|
16
|
+
logs the name of the output image, prompt, and prompt args to the terminal and files
|
|
17
|
+
"""
|
|
18
|
+
output_cntr = write_log_message(results, output_cntr)
|
|
19
|
+
write_log_files(results, log_path, file_types)
|
|
20
|
+
return output_cntr
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def write_log_message(results, output_cntr):
|
|
24
|
+
"""logs to the terminal"""
|
|
25
|
+
if len(results) == 0:
|
|
26
|
+
return output_cntr
|
|
27
|
+
log_lines = [f"{path}: {prompt}\n" for path, prompt in results]
|
|
28
|
+
if len(log_lines)>1:
|
|
29
|
+
subcntr = 1
|
|
30
|
+
for l in log_lines:
|
|
31
|
+
print(f"[{output_cntr}.{subcntr}] {l}", end="")
|
|
32
|
+
subcntr += 1
|
|
33
|
+
else:
|
|
34
|
+
print(f"[{output_cntr}] {log_lines[0]}", end="")
|
|
35
|
+
return output_cntr+1
|
|
36
|
+
|
|
37
|
+
def write_log_files(results, log_path, file_types):
|
|
38
|
+
for file_type in file_types:
|
|
39
|
+
if file_type == "txt":
|
|
40
|
+
write_log_txt(log_path, results)
|
|
41
|
+
elif file_type == "md" or file_type == "markdown":
|
|
42
|
+
write_log_markdown(log_path, results)
|
|
43
|
+
else:
|
|
44
|
+
print(f"'{file_type}' format is not supported, so write in plain text")
|
|
45
|
+
write_log_default(log_path, results, file_type)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def write_log_default(log_path, results, file_type):
|
|
49
|
+
plain_txt_lines = [f"{path}: {prompt}\n" for path, prompt in results]
|
|
50
|
+
with open(log_path + "." + file_type, "a", encoding="utf-8") as file:
|
|
51
|
+
file.writelines(plain_txt_lines)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def write_log_txt(log_path, results):
|
|
55
|
+
txt_lines = [f"{path}: {prompt}\n" for path, prompt in results]
|
|
56
|
+
with open(log_path + ".txt", "a", encoding="utf-8") as file:
|
|
57
|
+
file.writelines(txt_lines)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def write_log_markdown(log_path, results):
|
|
61
|
+
md_lines = []
|
|
62
|
+
for path, prompt in results:
|
|
63
|
+
file_name = os.path.basename(path)
|
|
64
|
+
md_lines.append(f"## {file_name}\n\n\n{prompt}\n")
|
|
65
|
+
with open(log_path + ".md", "a", encoding="utf-8") as file:
|
|
66
|
+
file.writelines(md_lines)
|