Since I've gotten started I've had to learn a few things even though some of it may eventually become useless or need to be repurposed and integrated once I start picking up comfyui, but for my Forge/A1111 WebUi brothers I have a set of scripts that may help you.
Prompt Generation: Randomize, Fluctuate, and Control Weight and Prompt Tags.
So this first bit is all about Large Batch prompt tasks. When I have nothing queued up to be produced, it means I can experiment with prompts, Lora's, checkpoints, and break stuff with pure throughput generation looking for interesting image subsets or tag/weights to use for more specific higher level generation.
This is where my Batch Prompt Generator comes in handy. It takes a simple text file with custom keyword arguments and puts them through a python script to give large batches of prompt outputs.
As an example:
$Random_tag() This sets up a set of tags or groups of tags to be chosen at random every time it generates a prompt.
Further we can augment it's behavior like so
$random_tag((Hat, Hood),(&(Scarf, Sunglasses, Headband)&), (Facemask))$
This should output one of the following:
Hat, Hood
(Scarf, Sunglasses, Headband)
Facemask
You can also do things more advanced than this, like swapping or randomly adding different Lora tags etc.
Random Numbers and Controlled Numbers
The next are far more simple and just mathematic functions I initially used to try and manipulate slider Lora for video frame generation.
&sine_wav, 2, -2, 60, 2& -- This script generates numbers in a wave pattern between 2 and -2 over the period of 60 prompt generations with a percision of 2 decimal places: 0.00. The idea being you can shift between the extremes of weights over a controlled period of generations.
&rand, 2, -2, 2& -- Much the same, just generates a random number between 2 and -2 up to .00 decimal places.
Process Control and Large Batch Control Tags
Another thing I decided I needed, and someone might find useful, is being able to stop adding or start adding certain tags into the prompts they are generating after certain number of prompts generated. The idea being that say if you have a Lora or Prompt meant to start walking, you could drop the walking tag and start a running one at the same time in a large batch of prompts.
$start 5, $top 10 -- This will start a prompt it is contained in after 5 generated prompts, and stop adding it to further prompts after 10 generations.
The last bit of this script pulls all of these commands and supportive syntax out of the batch generations so you can just plug and go.
How to use
First you need two text files to make a .bat and a .py
process_prompts.bat
@echo off
echo Enter the path to the input file containing prompts:
set /p input_file=
echo Enter the name for the new output text file (without extension):
set /p output_file_name=
echo Enter the total number of generations to process:
set /p total_generations=
python process_prompts.py "%input_file%" "%output_file_name%.txt" "%total_generations%"
echo Processing complete.
pause
process_prompts.py
import sys
import re
import math
import random
def sine_wave(index, total, min_weight, max_weight, angle, precision):
amplitude = (max_weight - min_weight) / 2
midline = (max_weight + min_weight) / 2
angle_rad = math.radians(angle)
weight = midline + amplitude * math.sin(angle_rad * (index / total) * 2 * math.pi)
return round(weight, precision)
def random_weight(min_weight, max_weight, precision):
weight = random.uniform(min_weight, max_weight)
return round(weight, precision)
def random_tag(tags):
processed_tags = []
buffer = ""
depth = 0 # Depth of nested parentheses
special_format = False # Whether we are in a special format group
i = 0
while i < len(tags):
char = tags[i]
# Check for special format toggle
if char == '&' and (i == 0 or tags[i-1] != '\\') and (i+1 < len(tags) and tags[i+1] == '('):
special_format = not special_format
i += 1 # Skip '&' and '('
continue
elif char == '&' and (i+1 < len(tags) and tags[i+1] == ')'):
i += 1 # Skip '&' and ')'
special_format = not special_format
continue
if char == '(':
depth += 1
elif char == ')':
depth -= 1
if depth == 0 and special_format:
# Special format: Keep parentheses in output
processed_tags.append(buffer + char)
buffer = ""
continue
if char == ',' and depth == 0:
if buffer.strip():
processed_tags.append(buffer.strip())
buffer = ""
else:
buffer += char
i += 1
if buffer.strip():
processed_tags.append(buffer.strip())
chosen_tag = random.choice(processed_tags).strip()
# Post-process to remove outer parentheses if not in special format
if chosen_tag.startswith('(') and chosen_tag.endswith(')') and not special_format:
return chosen_tag[1:-1]
return chosen_tag
def process_prompt(prompt, index, total_generations):
sine_wave_pattern = re.compile(r"&sine_wav, (-?\d+\.?\d*), (-?\d+\.?\d*), (-?\d+\.?\d*), (\d+)&")
random_weight_pattern = re.compile(r"&Rand, (-?\d+\.?\d*), (-?\d+\.?\d*)&")
random_tag_pattern = re.compile(r"\$random_tag\((.*?)\)\$")
directive_pattern = re.compile(r"(<[^<>]*\$(top|tart) \d+[^<>]*>)")
def check_visibility(match):
content = match.group(0)
directive, number = re.search(r"\$(top|tart) (\d+)", content).groups()
threshold = int(number)
if (directive == "top" and index >= threshold) or (directive == "tart" and index < threshold):
return ""
return content
prompt = re.sub(directive_pattern, check_visibility, prompt)
prompt = re.sub(sine_wave_pattern, lambda m: str(sine_wave(index, total_generations, float(m.group(2)), float(m.group(1)), float(m.group(3)), int(m.group(4)))), prompt)
prompt = re.sub(random_weight_pattern, lambda m: str(random_weight(float(m.group(1)), float(m.group(2)), 2)), prompt)
prompt = re.sub(random_tag_pattern, lambda m: random_tag(m.group(1)), prompt)
prompt = re.sub(r"\$top \d+|\$tart \d+|\$[^$]*\$", "", prompt)
return prompt
def main(input_file, output_file, total_generations):
with open(input_file, 'r') as file:
prompts = file.readlines()
processed_prompts = []
for index in range(total_generations):
for prompt in prompts:
processed_prompt = process_prompt(prompt.strip(), index, total_generations)
processed_prompts.append(processed_prompt)
with open(output_file, 'w') as file:
file.write("\n".join(processed_prompts))
if __name__ == "__main__":
input_file = sys.argv[1]
output_file = sys.argv[2]
total_generations = int(sys.argv[3])
main(input_file, output_file, total_generations)
Next just make a text file with your guide prompt that you want iterated, copy its path, run the .bat, use the path, name the new text file output in the command window, and how many generations you want it to make and your good to go.
You can then drag and drop the new text file (assuming you didn't make a syntax error) and you now have hours and hours of generation time when you're otherwise not wanting to either manually or handling more sensitive generation tweaking.