stable-diffusion-webui
stable-diffusion-webui copied to clipboard
{X}, {Y} syntax in prompt S/R
Is your feature request related to a problem? Please describe.
At the moment prompt S/R is quite powerful, but if you attempt to make, say, a matrix of artist combinations:
a painting by <artist_1>, <artist_2>, there will be a problem, because second S/R will replace results of the first, plus it is not always convenient to have a full name for S/R. And if you use placeholders like _1, _2 to denote each argument, those will result in wasted columns.
Describe the solution you'd like Would be nice to have two new S/R types added - {X} and {Y}. When either of those selected, prompt will be processed through string formatting and {X}/{Y} (depending on which one is picked) will be replaced by an item from the list.
I.e. you'd be able to do painting by {X}, then pick {X} as one of S/R options, and provide a list of artists there.
Describe alternatives you've considered I've written my own grid2d script, however it is not great and has redundant functionality compared to Prompt S/R. The script is attached.
Additional context I've attached the "grid2d" script I made based on other scripts. grid_2d.tar.gz
Grid_2d script in text form
import math
from collections import namedtuple
from copy import copy
import random
import modules.scripts as scripts
import gradio as gr
from modules import images
from modules.processing import process_images, Processed
from modules.shared import opts, cmd_opts, state
import modules.shared as shared
import modules.sd_samplers
def draw_xy_grid(p, xs, ys, x_labels, y_labels, cell, draw_legend):
res = []
ver_texts = [[images.GridAnnotation(y)] for y in y_labels]
hor_texts = [[images.GridAnnotation(x)] for x in x_labels]
first_processed = None
state.job_count = len(xs) * len(ys) * p.n_iter
for iy, y in enumerate(ys):
for ix, x in enumerate(xs):
state.job = f"{ix + iy * len(xs) + 1} out of {len(xs) * len(ys)}"
processed = cell(x, y)
if first_processed is None:
first_processed = processed
res.append(processed.images[0])
grid = images.image_grid(res, rows=len(ys))
if draw_legend:
grid = images.draw_grid_annotations(grid, res[0].width, res[0].height, hor_texts, ver_texts)
first_processed.images = [grid]
return first_processed
class Script(scripts.Script):
def title(self):
return "Grid 2d"
def ui(self, is_img2img):
x_values = gr.Textbox(label="X values", visible=False, lines=1)
y_values = gr.Textbox(label="Y values", visible=False, lines=1)
draw_legend = gr.Checkbox(label='Draw legend', value=True)
return [x_values, y_values, draw_legend]
def run(self, p, x_values, y_values, draw_legend):
modules.processing.fix_seed(p)
print(x_values)
print(y_values)
original_prompt = p.prompt[0] if type(p.prompt) == list else p.prompt
all_prompts = []
xs = [x.strip() for x in x_values.splitlines()]#[x.strip() for x in x_values.split('|')]
ys = [x.strip() for x in y_values.splitlines()]#[x.strip() for x in y_values.split('|')]
print(xs, ys)
for iy in ys:
for ix in xs:
print(ix, iy)
def cell(x, y):
pc = copy(p)
pc.prompt = pc.prompt.replace('{x}', x)
pc.negative_prompt = pc.negative_prompt.replace('{x}', x)
pc.prompt = pc.prompt.replace('{y}', y)
pc.negative_prompt = pc.negative_prompt.replace('{y}', y)
return process_images(pc)
processed = draw_xy_grid(
p,
xs=xs,
ys=ys,
x_labels=xs,
y_labels=ys,
cell=cell,
draw_legend=draw_legend
)
if opts.grid_save:
images.save_image(processed.images[0], p.outpath_grids, "xy_grid", prompt=p.prompt, seed=processed.seed,
grid=True, p=p)
# restore checkpoint in case it was changed by axes
modules.sd_models.reload_model_weights(shared.sd_model)
return processed
SD doesn't care about case but S/R is case sensitive. So you'd want to do the following:
artist1 x ARTIST9000 artist2 x ARTIST8900 ... artist9000 x ARTIST1
etc.
more info in wiki showcase