Spaces:
Paused
Paused
lllyasviel
commited on
Commit
•
796cb1f
1
Parent(s):
2f3af37
1.0.20 (#35)
Browse filesRe-write UI to use async codes: (1) for faster start, and (2) for better live preview.
Removed opencv dependency
Plan to support Linux soon
- fooocus_version.py +1 -1
- modules/async_worker.py +77 -0
- modules/core.py +10 -14
- modules/cv2win32.py +0 -43
- modules/html.py +84 -0
- requirements_versions.txt +1 -1
- update_log.md +6 -0
- webui.py +42 -58
fooocus_version.py
CHANGED
@@ -1 +1 @@
|
|
1 |
-
version = '1.0.
|
|
|
1 |
+
version = '1.0.20'
|
modules/async_worker.py
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import threading
|
2 |
+
|
3 |
+
|
4 |
+
buffer = []
|
5 |
+
outputs = []
|
6 |
+
|
7 |
+
|
8 |
+
def worker():
|
9 |
+
global buffer, outputs
|
10 |
+
|
11 |
+
import time
|
12 |
+
import random
|
13 |
+
import modules.default_pipeline as pipeline
|
14 |
+
import modules.path
|
15 |
+
|
16 |
+
from PIL import Image
|
17 |
+
from modules.sdxl_styles import apply_style, aspect_ratios
|
18 |
+
from modules.util import generate_temp_filename
|
19 |
+
|
20 |
+
def handler(task):
|
21 |
+
prompt, negative_prompt, style_selction, performance_selction, \
|
22 |
+
aspect_ratios_selction, image_number, image_seed, base_model_name, refiner_model_name, \
|
23 |
+
l1, w1, l2, w2, l3, w3, l4, w4, l5, w5 = task
|
24 |
+
|
25 |
+
loras = [(l1, w1), (l2, w2), (l3, w3), (l4, w4), (l5, w5)]
|
26 |
+
|
27 |
+
pipeline.refresh_base_model(base_model_name)
|
28 |
+
pipeline.refresh_refiner_model(refiner_model_name)
|
29 |
+
pipeline.refresh_loras(loras)
|
30 |
+
|
31 |
+
p_txt, n_txt = apply_style(style_selction, prompt, negative_prompt)
|
32 |
+
|
33 |
+
if performance_selction == 'Speed':
|
34 |
+
steps = 30
|
35 |
+
switch = 20
|
36 |
+
else:
|
37 |
+
steps = 60
|
38 |
+
switch = 40
|
39 |
+
|
40 |
+
width, height = aspect_ratios[aspect_ratios_selction]
|
41 |
+
|
42 |
+
results = []
|
43 |
+
seed = image_seed
|
44 |
+
if not isinstance(seed, int) or seed < 0 or seed > 65535:
|
45 |
+
seed = random.randint(1, 65535)
|
46 |
+
|
47 |
+
all_steps = steps * image_number
|
48 |
+
|
49 |
+
def callback(step, x0, x, total_steps, y):
|
50 |
+
done_steps = i * steps + step
|
51 |
+
outputs.append(['preview', (
|
52 |
+
int(100.0 * float(done_steps) / float(all_steps)),
|
53 |
+
f'Step {step}/{total_steps} in the {i}-th Sampling',
|
54 |
+
y)])
|
55 |
+
|
56 |
+
for i in range(image_number):
|
57 |
+
imgs = pipeline.process(p_txt, n_txt, steps, switch, width, height, seed, callback=callback)
|
58 |
+
|
59 |
+
for x in imgs:
|
60 |
+
local_temp_filename = generate_temp_filename(folder=modules.path.temp_outputs_path, extension='png')
|
61 |
+
Image.fromarray(x).save(local_temp_filename)
|
62 |
+
|
63 |
+
seed += 1
|
64 |
+
results += imgs
|
65 |
+
|
66 |
+
outputs.append(['results', results])
|
67 |
+
return
|
68 |
+
|
69 |
+
while True:
|
70 |
+
time.sleep(0.01)
|
71 |
+
if len(buffer) > 0:
|
72 |
+
task = buffer.pop(0)
|
73 |
+
handler(task)
|
74 |
+
pass
|
75 |
+
|
76 |
+
|
77 |
+
threading.Thread(target=worker, daemon=True).start()
|
modules/core.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1 |
import os
|
2 |
import random
|
3 |
-
import cv2
|
4 |
import einops
|
5 |
import torch
|
6 |
import numpy as np
|
@@ -8,12 +7,11 @@ import numpy as np
|
|
8 |
import comfy.model_management
|
9 |
import comfy.utils
|
10 |
|
11 |
-
from comfy.sd import load_checkpoint_guess_config
|
12 |
from nodes import VAEDecode, EmptyLatentImage, CLIPTextEncode
|
13 |
from comfy.sample import prepare_mask, broadcast_cond, load_additional_models, cleanup_additional_models
|
14 |
from modules.samplers_advanced import KSampler, KSamplerWithRefiner
|
15 |
from modules.adm_patch import patch_negative_adm
|
16 |
-
from modules.cv2win32 import show_preview
|
17 |
|
18 |
|
19 |
patch_negative_adm()
|
@@ -86,11 +84,7 @@ def get_previewer(device, latent_format):
|
|
86 |
x_sample = taesd.decoder(torch.nn.functional.avg_pool2d(x0, kernel_size=(2, 2))).detach() * 255.0
|
87 |
x_sample = einops.rearrange(x_sample, 'b c h w -> b h w c')
|
88 |
x_sample = x_sample.cpu().numpy().clip(0, 255).astype(np.uint8)
|
89 |
-
|
90 |
-
if i > 0:
|
91 |
-
show_preview(f'cv2_preview_{i}', s, title=f'Preview Image {i}, step = [{step}/{total_steps}')
|
92 |
-
else:
|
93 |
-
show_preview(f'cv2_preview_{i}', s, title=f'Preview Image, step = {step}/{total_steps}')
|
94 |
|
95 |
taesd.preview = preview_function
|
96 |
|
@@ -126,10 +120,11 @@ def ksampler(model, positive, negative, latent, seed=None, steps=30, cfg=7.0, sa
|
|
126 |
pbar = comfy.utils.ProgressBar(steps)
|
127 |
|
128 |
def callback(step, x0, x, total_steps):
|
129 |
-
|
130 |
-
callback_function(step, x0, x, total_steps)
|
131 |
if previewer and step % 3 == 0:
|
132 |
-
previewer.preview(x0, step, total_steps)
|
|
|
|
|
133 |
pbar.update_absolute(step + 1, total_steps, None)
|
134 |
|
135 |
sigmas = None
|
@@ -197,10 +192,11 @@ def ksampler_with_refiner(model, positive, negative, refiner, refiner_positive,
|
|
197 |
pbar = comfy.utils.ProgressBar(steps)
|
198 |
|
199 |
def callback(step, x0, x, total_steps):
|
200 |
-
|
201 |
-
callback_function(step, x0, x, total_steps)
|
202 |
if previewer and step % 3 == 0:
|
203 |
-
previewer.preview(x0, step, total_steps)
|
|
|
|
|
204 |
pbar.update_absolute(step + 1, total_steps, None)
|
205 |
|
206 |
sigmas = None
|
|
|
1 |
import os
|
2 |
import random
|
|
|
3 |
import einops
|
4 |
import torch
|
5 |
import numpy as np
|
|
|
7 |
import comfy.model_management
|
8 |
import comfy.utils
|
9 |
|
10 |
+
from comfy.sd import load_checkpoint_guess_config
|
11 |
from nodes import VAEDecode, EmptyLatentImage, CLIPTextEncode
|
12 |
from comfy.sample import prepare_mask, broadcast_cond, load_additional_models, cleanup_additional_models
|
13 |
from modules.samplers_advanced import KSampler, KSamplerWithRefiner
|
14 |
from modules.adm_patch import patch_negative_adm
|
|
|
15 |
|
16 |
|
17 |
patch_negative_adm()
|
|
|
84 |
x_sample = taesd.decoder(torch.nn.functional.avg_pool2d(x0, kernel_size=(2, 2))).detach() * 255.0
|
85 |
x_sample = einops.rearrange(x_sample, 'b c h w -> b h w c')
|
86 |
x_sample = x_sample.cpu().numpy().clip(0, 255).astype(np.uint8)
|
87 |
+
return x_sample[0]
|
|
|
|
|
|
|
|
|
88 |
|
89 |
taesd.preview = preview_function
|
90 |
|
|
|
120 |
pbar = comfy.utils.ProgressBar(steps)
|
121 |
|
122 |
def callback(step, x0, x, total_steps):
|
123 |
+
y = None
|
|
|
124 |
if previewer and step % 3 == 0:
|
125 |
+
y = previewer.preview(x0, step, total_steps)
|
126 |
+
if callback_function is not None:
|
127 |
+
callback_function(step, x0, x, total_steps, y)
|
128 |
pbar.update_absolute(step + 1, total_steps, None)
|
129 |
|
130 |
sigmas = None
|
|
|
192 |
pbar = comfy.utils.ProgressBar(steps)
|
193 |
|
194 |
def callback(step, x0, x, total_steps):
|
195 |
+
y = None
|
|
|
196 |
if previewer and step % 3 == 0:
|
197 |
+
y = previewer.preview(x0, step, total_steps)
|
198 |
+
if callback_function is not None:
|
199 |
+
callback_function(step, x0, x, total_steps, y)
|
200 |
pbar.update_absolute(step + 1, total_steps, None)
|
201 |
|
202 |
sigmas = None
|
modules/cv2win32.py
DELETED
@@ -1,43 +0,0 @@
|
|
1 |
-
import threading
|
2 |
-
import cv2
|
3 |
-
import os
|
4 |
-
|
5 |
-
|
6 |
-
buffer = []
|
7 |
-
|
8 |
-
|
9 |
-
def worker():
|
10 |
-
global buffer
|
11 |
-
try:
|
12 |
-
while True:
|
13 |
-
cv2.waitKey(50)
|
14 |
-
if len(buffer) > 0:
|
15 |
-
task = buffer.pop(0)
|
16 |
-
if task is None:
|
17 |
-
cv2.destroyAllWindows()
|
18 |
-
else:
|
19 |
-
flag, img, title = task
|
20 |
-
cv2.imshow(flag, img)
|
21 |
-
cv2.setWindowTitle(flag, title)
|
22 |
-
cv2.setWindowProperty(flag, cv2.WND_PROP_TOPMOST, 1)
|
23 |
-
except Exception as e:
|
24 |
-
print('Failed to open preview window. You are not using a local device with GUI support.')
|
25 |
-
print(e)
|
26 |
-
pass
|
27 |
-
|
28 |
-
|
29 |
-
def save_image(path, img):
|
30 |
-
os.makedirs(os.path.dirname(path), exist_ok=True)
|
31 |
-
cv2.imwrite(path, img[..., ::-1].copy())
|
32 |
-
print(f'Image saved: {path}')
|
33 |
-
|
34 |
-
|
35 |
-
def show_preview(flag, img, title='preview'):
|
36 |
-
buffer.append((flag, img[..., ::-1].copy(), title))
|
37 |
-
|
38 |
-
|
39 |
-
def close_all_preview():
|
40 |
-
buffer.append(None)
|
41 |
-
|
42 |
-
|
43 |
-
threading.Thread(target=worker, daemon=True).start()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
modules/html.py
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
css = '''
|
2 |
+
.loader-container {
|
3 |
+
display: flex; /* Use flex to align items horizontally */
|
4 |
+
align-items: center; /* Center items vertically within the container */
|
5 |
+
white-space: nowrap; /* Prevent line breaks within the container */
|
6 |
+
}
|
7 |
+
|
8 |
+
.loader {
|
9 |
+
border: 8px solid #f3f3f3; /* Light grey */
|
10 |
+
border-top: 8px solid #3498db; /* Blue */
|
11 |
+
border-radius: 50%;
|
12 |
+
width: 30px;
|
13 |
+
height: 30px;
|
14 |
+
animation: spin 2s linear infinite;
|
15 |
+
}
|
16 |
+
|
17 |
+
@keyframes spin {
|
18 |
+
0% { transform: rotate(0deg); }
|
19 |
+
100% { transform: rotate(360deg); }
|
20 |
+
}
|
21 |
+
|
22 |
+
/* Style the progress bar */
|
23 |
+
progress {
|
24 |
+
appearance: none; /* Remove default styling */
|
25 |
+
height: 20px; /* Set the height of the progress bar */
|
26 |
+
border-radius: 5px; /* Round the corners of the progress bar */
|
27 |
+
background-color: #f3f3f3; /* Light grey background */
|
28 |
+
width: 100%;
|
29 |
+
}
|
30 |
+
|
31 |
+
/* Style the progress bar container */
|
32 |
+
.progress-container {
|
33 |
+
margin-left: 20px;
|
34 |
+
margin-right: 20px;
|
35 |
+
flex-grow: 1; /* Allow the progress container to take up remaining space */
|
36 |
+
}
|
37 |
+
|
38 |
+
/* Set the color of the progress bar fill */
|
39 |
+
progress::-webkit-progress-value {
|
40 |
+
background-color: #3498db; /* Blue color for the fill */
|
41 |
+
}
|
42 |
+
|
43 |
+
progress::-moz-progress-bar {
|
44 |
+
background-color: #3498db; /* Blue color for the fill in Firefox */
|
45 |
+
}
|
46 |
+
|
47 |
+
/* Style the text on the progress bar */
|
48 |
+
progress::after {
|
49 |
+
content: attr(value '%'); /* Display the progress value followed by '%' */
|
50 |
+
position: absolute;
|
51 |
+
top: 50%;
|
52 |
+
left: 50%;
|
53 |
+
transform: translate(-50%, -50%);
|
54 |
+
color: white; /* Set text color */
|
55 |
+
font-size: 14px; /* Set font size */
|
56 |
+
}
|
57 |
+
|
58 |
+
/* Style other texts */
|
59 |
+
.loader-container > span {
|
60 |
+
margin-left: 5px; /* Add spacing between the progress bar and the text */
|
61 |
+
}
|
62 |
+
|
63 |
+
.progress-bar > .generating {
|
64 |
+
display: none !important;
|
65 |
+
}
|
66 |
+
|
67 |
+
.progress-bar{
|
68 |
+
height: 30px !important;
|
69 |
+
}
|
70 |
+
|
71 |
+
'''
|
72 |
+
progress_html = '''
|
73 |
+
<div class="loader-container">
|
74 |
+
<div class="loader"></div>
|
75 |
+
<div class="progress-container">
|
76 |
+
<progress value="*number*" max="100"></progress>
|
77 |
+
</div>
|
78 |
+
<span>*text*</span>
|
79 |
+
</div>
|
80 |
+
'''
|
81 |
+
|
82 |
+
|
83 |
+
def make_progress_html(number, text):
|
84 |
+
return progress_html.replace('*number*', str(number)).replace('*text*', text)
|
requirements_versions.txt
CHANGED
@@ -8,8 +8,8 @@ Pillow==9.2.0
|
|
8 |
scipy==1.9.3
|
9 |
tqdm==4.64.1
|
10 |
psutil==5.9.5
|
11 |
-
opencv-python==4.7.0.72
|
12 |
numpy==1.23.5
|
13 |
pytorch_lightning==1.9.4
|
14 |
omegaconf==2.2.3
|
15 |
gradio==3.39.0
|
|
|
|
8 |
scipy==1.9.3
|
9 |
tqdm==4.64.1
|
10 |
psutil==5.9.5
|
|
|
11 |
numpy==1.23.5
|
12 |
pytorch_lightning==1.9.4
|
13 |
omegaconf==2.2.3
|
14 |
gradio==3.39.0
|
15 |
+
pygit2==1.12.2
|
update_log.md
CHANGED
@@ -1,3 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
### 1.0.19
|
2 |
|
3 |
* Unlock to allow changing model.
|
|
|
1 |
+
### 1.0.20
|
2 |
+
|
3 |
+
* Re-write UI to use async codes: (1) for faster start, and (2) for better live preview.
|
4 |
+
* Removed opencv dependency
|
5 |
+
* Plan to support Linux soon
|
6 |
+
|
7 |
### 1.0.19
|
8 |
|
9 |
* Unlock to allow changing model.
|
webui.py
CHANGED
@@ -1,65 +1,49 @@
|
|
1 |
import gradio as gr
|
|
|
|
|
2 |
import modules.path
|
3 |
-
import random
|
4 |
import fooocus_version
|
5 |
-
import modules.
|
6 |
-
|
7 |
-
|
8 |
-
from modules.
|
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 |
-
def callback(step, x0, x, total_steps):
|
41 |
-
done_steps = i * steps + step
|
42 |
-
progress(float(done_steps) / float(all_steps), f'Step {step}/{total_steps} in the {i}-th Sampling')
|
43 |
-
|
44 |
-
for i in range(image_number):
|
45 |
-
imgs = pipeline.process(p_txt, n_txt, steps, switch, width, height, seed, callback=callback)
|
46 |
-
|
47 |
-
for x in imgs:
|
48 |
-
local_temp_filename = generate_temp_filename(folder=modules.path.temp_outputs_path, extension='png')
|
49 |
-
save_image(local_temp_filename, x)
|
50 |
-
|
51 |
-
seed += 1
|
52 |
-
results += imgs
|
53 |
-
|
54 |
-
close_all_preview()
|
55 |
-
return results
|
56 |
-
|
57 |
-
|
58 |
-
block = gr.Blocks(title='Fooocus ' + fooocus_version.version).queue()
|
59 |
with block:
|
60 |
with gr.Row():
|
61 |
with gr.Column():
|
62 |
-
|
|
|
|
|
63 |
with gr.Row():
|
64 |
with gr.Column(scale=0.85):
|
65 |
prompt = gr.Textbox(show_label=False, placeholder="Type prompt here.", container=False, autofocus=True)
|
@@ -107,6 +91,6 @@ with block:
|
|
107 |
performance_selction, aspect_ratios_selction, image_number, image_seed
|
108 |
]
|
109 |
ctrls += [base_model, refiner_model] + lora_ctrls
|
110 |
-
run_button.click(fn=generate_clicked, inputs=ctrls, outputs=[gallery])
|
111 |
|
112 |
-
block.launch(inbrowser=True)
|
|
|
1 |
import gradio as gr
|
2 |
+
import sys
|
3 |
+
import time
|
4 |
import modules.path
|
|
|
5 |
import fooocus_version
|
6 |
+
import modules.html
|
7 |
+
import modules.async_worker as worker
|
8 |
+
|
9 |
+
from modules.sdxl_styles import style_keys, aspect_ratios
|
10 |
+
|
11 |
+
|
12 |
+
def generate_clicked(*args):
|
13 |
+
yield gr.update(interactive=False), \
|
14 |
+
gr.update(visible=True, value=modules.html.make_progress_html(1, 'Processing text encoding ...')), \
|
15 |
+
gr.update(visible=True, value=None), \
|
16 |
+
gr.update(visible=False)
|
17 |
+
|
18 |
+
worker.buffer.append(list(args))
|
19 |
+
finished = False
|
20 |
+
|
21 |
+
while not finished:
|
22 |
+
time.sleep(0.01)
|
23 |
+
if len(worker.outputs) > 0:
|
24 |
+
flag, product = worker.outputs.pop(0)
|
25 |
+
if flag == 'preview':
|
26 |
+
percentage, title, image = product
|
27 |
+
yield gr.update(interactive=False), \
|
28 |
+
gr.update(visible=True, value=modules.html.make_progress_html(percentage, title)), \
|
29 |
+
gr.update(visible=True, value=image) if image is not None else gr.update(), \
|
30 |
+
gr.update(visible=False)
|
31 |
+
if flag == 'results':
|
32 |
+
yield gr.update(interactive=True), \
|
33 |
+
gr.update(visible=False), \
|
34 |
+
gr.update(visible=False), \
|
35 |
+
gr.update(visible=True, value=product)
|
36 |
+
finished = True
|
37 |
+
return
|
38 |
+
|
39 |
+
|
40 |
+
block = gr.Blocks(title='Fooocus ' + fooocus_version.version, css=modules.html.css).queue()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
with block:
|
42 |
with gr.Row():
|
43 |
with gr.Column():
|
44 |
+
progress_window = gr.Image(label='Preview', show_label=True, height=640, visible=False)
|
45 |
+
progress_html = gr.HTML(value=modules.html.make_progress_html(32, 'Progress 32%'), visible=False, elem_id='progress-bar', elem_classes='progress-bar')
|
46 |
+
gallery = gr.Gallery(label='Gallery', show_label=False, object_fit='contain', height=720, visible=True)
|
47 |
with gr.Row():
|
48 |
with gr.Column(scale=0.85):
|
49 |
prompt = gr.Textbox(show_label=False, placeholder="Type prompt here.", container=False, autofocus=True)
|
|
|
91 |
performance_selction, aspect_ratios_selction, image_number, image_seed
|
92 |
]
|
93 |
ctrls += [base_model, refiner_model] + lora_ctrls
|
94 |
+
run_button.click(fn=generate_clicked, inputs=ctrls, outputs=[run_button, progress_html, progress_window, gallery])
|
95 |
|
96 |
+
block.launch(inbrowser=True, server_name='0.0.0.0' if '--listen' in sys.argv else None)
|