Skip to content

Commit 1a775ed

Browse files
committed
Added support for wildcards (ported from RuinedFooocus, adjusted to Fooocus V2)
1 parent b028acf commit 1a775ed

File tree

7 files changed

+87
-37
lines changed

7 files changed

+87
-37
lines changed

modules/async_worker.py

+41-34
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def worker():
4444
import modules.virtual_memory as virtual_memory
4545

4646
from modules.resolutions import get_resolution_string, resolutions
47-
from modules.sdxl_styles import apply_style
47+
from modules.sdxl_styles import apply_style, apply_wildcards
4848
from modules.private_logger import log
4949
from modules.expansion import safe_str
5050
from modules.util import join_prompts, remove_empty_str
@@ -154,68 +154,72 @@ def handler(task):
154154

155155

156156
progressbar(5, 'Processing prompts ...')
157+
tasks = []
158+
for i in range(image_number):
159+
positive_basic_workloads = []
160+
negative_basic_workloads = []
161+
task_seed = seed if same_seed_for_all else seed + i
162+
task_prompt = apply_wildcards(prompt, task_seed)
163+
164+
if use_style:
165+
for s in style_selections:
166+
p, n = apply_style(s, positive=task_prompt)
167+
positive_basic_workloads.append(p)
168+
negative_basic_workloads.append(n)
169+
else:
170+
positive_basic_workloads.append(task_prompt)
171+
172+
negative_basic_workloads.append(negative_prompt) # Always use independent workload for negative.
157173

158-
positive_basic_workloads = []
159-
negative_basic_workloads = []
160-
161-
if use_style:
162-
for s in style_selections:
163-
p, n = apply_style(s, positive=prompt)
164-
positive_basic_workloads.append(p)
165-
negative_basic_workloads.append(n)
166-
else:
167-
positive_basic_workloads.append(prompt)
168-
169-
negative_basic_workloads.append(negative_prompt) # Always use independent workload for negative.
170-
171-
positive_basic_workloads = positive_basic_workloads + extra_positive_prompts
172-
negative_basic_workloads = negative_basic_workloads + extra_negative_prompts
174+
positive_basic_workloads = positive_basic_workloads + extra_positive_prompts
175+
negative_basic_workloads = negative_basic_workloads + extra_negative_prompts
173176

174-
positive_basic_workloads = remove_empty_str(positive_basic_workloads, default=prompt)
175-
negative_basic_workloads = remove_empty_str(negative_basic_workloads, default=negative_prompt)
177+
positive_basic_workloads = remove_empty_str(positive_basic_workloads, default=task_prompt)
178+
negative_basic_workloads = remove_empty_str(negative_basic_workloads, default=negative_prompt)
176179

177-
positive_top_k = len(positive_basic_workloads)
178-
negative_top_k = len(negative_basic_workloads)
180+
tasks.append(dict(
181+
task_seed=task_seed,
182+
prompt=task_prompt,
183+
positive=positive_basic_workloads,
184+
negative=negative_basic_workloads,
185+
positive_top_k=len(positive_basic_workloads),
186+
negative_top_k=len(negative_basic_workloads),
187+
expansion='',
188+
c=[None, None],
189+
uc=[None, None]
190+
))
179191

180-
tasks = [dict(
181-
task_seed=seed if same_seed_for_all else seed + i,
182-
positive=positive_basic_workloads,
183-
negative=negative_basic_workloads,
184-
expansion='',
185-
c=[None, None],
186-
uc=[None, None],
187-
) for i in range(image_number)]
188192

189193
if use_expansion:
190194
for i, t in enumerate(tasks):
191195
progressbar(5, f'Preparing Fooocus text #{i + 1} ...')
192-
expansion = pipeline.expansion(prompt, t['task_seed'])
196+
expansion = pipeline.expansion(t['prompt'], t['task_seed'])
193197
print(f'[Prompt Expansion] New suffix: {expansion}')
194198
t['expansion'] = expansion
195-
t['positive'] = copy.deepcopy(t['positive']) + [join_prompts(prompt, expansion)] # Deep copy.
199+
t['positive'] = copy.deepcopy(t['positive']) + [join_prompts(t['prompt'], expansion)] # Deep copy.
196200

197201
for i, t in enumerate(tasks):
198202
progressbar(7, f'Encoding base positive #{i + 1} ...')
199203
t['c'][0] = pipeline.clip_encode(sd=pipeline.xl_base_patched, texts=t['positive'],
200-
pool_top_k=positive_top_k)
204+
pool_top_k=t['positive_top_k'])
201205

202206
for i, t in enumerate(tasks):
203207
progressbar(9, f'Encoding base negative #{i + 1} ...')
204208
t['uc'][0] = pipeline.clip_encode(sd=pipeline.xl_base_patched, texts=t['negative'],
205-
pool_top_k=negative_top_k)
209+
pool_top_k=t['negative_top_k'])
206210

207211
if pipeline.xl_refiner is not None:
208212
virtual_memory.load_from_virtual_memory(pipeline.xl_refiner.clip.cond_stage_model)
209213

210214
for i, t in enumerate(tasks):
211215
progressbar(11, f'Encoding refiner positive #{i + 1} ...')
212216
t['c'][1] = pipeline.clip_encode(sd=pipeline.xl_refiner, texts=t['positive'],
213-
pool_top_k=positive_top_k)
217+
pool_top_k=t['positive_top_k'])
214218

215219
for i, t in enumerate(tasks):
216220
progressbar(13, f'Encoding refiner negative #{i + 1} ...')
217221
t['uc'][1] = pipeline.clip_encode(sd=pipeline.xl_refiner, texts=t['negative'],
218-
pool_top_k=negative_top_k)
222+
pool_top_k=t['negative_top_k'])
219223

220224
virtual_memory.try_move_to_virtual_memory(pipeline.xl_refiner.clip.cond_stage_model)
221225

@@ -307,6 +311,7 @@ def callback(step, x0, x, total_steps, y):
307311

308312
metadata = {
309313
'prompt': raw_prompt, 'negative_prompt': raw_negative_prompt, 'styles': raw_style_selections,
314+
'real_prompt': task['positive'], 'real_negative_prompt': task['negative'],
310315
'seed': task['task_seed'], 'width': width, 'height': height,
311316
'sampler': sampler_name, 'scheduler': scheduler, 'performance': performance,
312317
'steps': steps, 'switch': switch, 'sharpness': sharpness, 'cfg': cfg,
@@ -348,6 +353,8 @@ def callback(step, x0, x, total_steps, y):
348353
('Negative Prompt', raw_negative_prompt),
349354
('Fooocus V2 (Prompt Expansion)', task['expansion']),
350355
('Styles', str(raw_style_selections)),
356+
('Real Prompt', task['positive']),
357+
('Real Negative Prompt', task['negative']),
351358
('Seed', task['task_seed']),
352359
('Resolution', get_resolution_string(width, height)),
353360
('Performance', (performance, steps, switch)),

modules/path.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ def load_paths():
1313
path_vae_approx = '../models/vae_approx/'
1414
path_fooocus_expansion = '../models/prompt_expansion/fooocus_expansion/'
1515
path_styles = '../sdxl_styles/'
16+
path_wildcards = '../wildcards/'
1617
path_outputs = '../outputs/'
1718

1819
if exists('paths.json'):
@@ -35,6 +36,8 @@ def load_paths():
3536
path_fooocus_expansion = paths_obj['path_fooocus_expansion']
3637
if 'path_styles' in paths_obj:
3738
path_styles = paths_obj['path_styles']
39+
if 'path_wildcards' in paths_obj:
40+
path_wildcards = paths_obj['path_wildcards']
3841
if 'path_outputs' in paths_obj:
3942
path_outputs = paths_obj['path_outputs']
4043

@@ -43,10 +46,10 @@ def load_paths():
4346
finally:
4447
paths_file.close()
4548

46-
return path_checkpoints, path_loras, path_embeddings, path_clip_vision, path_controlnet, path_vae_approx, path_fooocus_expansion, path_styles, path_outputs
49+
return path_checkpoints, path_loras, path_embeddings, path_clip_vision, path_controlnet, path_vae_approx, path_fooocus_expansion, path_styles, path_wildcards, path_outputs
4750

4851

49-
path_checkpoints, path_loras, path_embeddings, path_clip_vision, path_controlnet, path_vae_approx, path_fooocus_expansion, path_styles, path_outputs = load_paths()
52+
path_checkpoints, path_loras, path_embeddings, path_clip_vision, path_controlnet, path_vae_approx, path_fooocus_expansion, path_styles, path_wildcards, path_outputs = load_paths()
5053

5154
modelfile_path = path_checkpoints if os.path.isabs(path_checkpoints) else os.path.abspath(os.path.join(os.path.dirname(__file__), path_checkpoints))
5255
lorafile_path = path_loras if os.path.isabs(path_loras) else os.path.abspath(os.path.join(os.path.dirname(__file__), path_loras))
@@ -56,6 +59,7 @@ def load_paths():
5659
vae_approx_path = path_vae_approx if os.path.isabs(path_vae_approx) else os.path.abspath(os.path.join(os.path.dirname(__file__), path_vae_approx))
5760
fooocus_expansion_path = path_fooocus_expansion if os.path.isabs(path_fooocus_expansion) else os.path.abspath(os.path.join(os.path.dirname(__file__), path_fooocus_expansion))
5861
styles_path = path_styles if os.path.isabs(path_styles) else os.path.abspath(os.path.join(os.path.dirname(__file__), path_styles))
62+
wildcards_path = path_wildcards if os.path.isabs(path_wildcards) else os.path.abspath(os.path.join(os.path.dirname(__file__), path_wildcards))
5963
temp_outputs_path = path_outputs if os.path.isabs(path_outputs) else os.path.abspath(os.path.join(os.path.dirname(__file__), path_outputs))
6064

6165
os.makedirs(temp_outputs_path, exist_ok=True)

modules/sdxl_styles.py

+19-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import os
22
import json
3+
import re
4+
import random
35

46
from os.path import exists
5-
from modules.path import styles_path, get_files_from_folder
7+
from modules.path import styles_path, wildcards_path, get_files_from_folder
68
from modules.util import join_prompts
79

810

@@ -84,3 +86,19 @@ def load_styles(filename=None, base_dict=None):
8486
def apply_style(style, positive):
8587
p, n = styles[style]
8688
return p.replace('{prompt}', positive), n
89+
90+
91+
92+
def apply_wildcards(wildcard_text, seed=None, directory=wildcards_path):
93+
placeholders = re.findall(r'__(\w+)__', wildcard_text)
94+
for placeholder in placeholders:
95+
try:
96+
with open(os.path.join(directory, f'{placeholder}.txt')) as f:
97+
words = f.read().splitlines()
98+
f.close()
99+
rng = random.Random(seed)
100+
wildcard_text = re.sub(rf'__{placeholder}__', rng.choice(words), wildcard_text)
101+
except IOError:
102+
print(f'Error: could not open wildcard file {placeholder}.txt, using as normal word.')
103+
wildcard_text = wildcard_text.replace(f'__{placeholder}__', placeholder)
104+
return wildcard_text

paths-example.json

+1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
"path_vae_approx": "../models/vae_approx/",
88
"path_fooocus_expansion": "../models/prompt_expansion/fooocus_expansion/",
99
"path_styles": "../sdxl_styles/",
10+
"path_wildcards": "../wildcards/",
1011
"path_outputs": "../outputs/"
1112
}

readme.md

+1
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ Below things are already inside the software, and **users do not need to do anyt
183183
25. Starting generation via Ctrl-ENTER hotkey (ported from SD web UI).
184184
26. Support for loading models from subfolders (ported from RuinedFooocus).
185185
27. Support for authentication in --share mode (credentials loaded from auth.json - use auth-example.json as a template).
186+
28. Support for wildcards (ported from RuinedFooocus - put them in wildcards folder, then try prompts like `__color__ sports car` with different seeds).
186187

187188
## Thanks
188189

update_log_mre.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
### 2.0.19 MRE
22

3+
* Added support for wildcards (ported from RuinedFooocus, adjusted to Fooocus V2).
4+
* Restored saving information about real prompt in metadata and log file (adjusted to Fooocus V2).
35
* Fixed links to log files not working with customized outputs path.
46
* Fixed calls to non-existing Comfy functions (vanilla still using old Comfy).
57

wildcards/color.txt

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
aqua
2+
black
3+
blue
4+
fuchsia
5+
gray
6+
green
7+
lime
8+
maroon
9+
navy
10+
olive
11+
orange
12+
purple
13+
red
14+
silver
15+
teal
16+
white
17+
yellow

0 commit comments

Comments
 (0)