Commit 9f267af3 authored by AUTOMATIC's avatar AUTOMATIC

added a second style field

added the ability to use {prompt} in styles
added a button to apply style to textbox
rearranged top row for UI
parent 6153d9d9
...@@ -11,7 +11,7 @@ from modules.ui import plaintext_to_html ...@@ -11,7 +11,7 @@ from modules.ui import plaintext_to_html
import modules.images as images import modules.images as images
import modules.scripts import modules.scripts
def img2img(prompt: str, negative_prompt: str, prompt_style: str, init_img, init_img_with_mask, init_mask, mask_mode, steps: int, sampler_index: int, mask_blur: int, inpainting_fill: int, restore_faces: bool, tiling: bool, mode: int, n_iter: int, batch_size: int, cfg_scale: float, denoising_strength: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, height: int, width: int, resize_mode: int, upscaler_index: str, upscale_overlap: int, inpaint_full_res: bool, inpainting_mask_invert: int, *args): def img2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: str, init_img, init_img_with_mask, init_mask, mask_mode, steps: int, sampler_index: int, mask_blur: int, inpainting_fill: int, restore_faces: bool, tiling: bool, mode: int, n_iter: int, batch_size: int, cfg_scale: float, denoising_strength: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, height: int, width: int, resize_mode: int, upscaler_index: str, upscale_overlap: int, inpaint_full_res: bool, inpainting_mask_invert: int, *args):
is_inpaint = mode == 1 is_inpaint = mode == 1
is_upscale = mode == 2 is_upscale = mode == 2
...@@ -37,7 +37,7 @@ def img2img(prompt: str, negative_prompt: str, prompt_style: str, init_img, init ...@@ -37,7 +37,7 @@ def img2img(prompt: str, negative_prompt: str, prompt_style: str, init_img, init
outpath_grids=opts.outdir_grids or opts.outdir_img2img_grids, outpath_grids=opts.outdir_grids or opts.outdir_img2img_grids,
prompt=prompt, prompt=prompt,
negative_prompt=negative_prompt, negative_prompt=negative_prompt,
prompt_style=prompt_style, styles=[prompt_style, prompt_style2],
seed=seed, seed=seed,
subseed=subseed, subseed=subseed,
subseed_strength=subseed_strength, subseed_strength=subseed_strength,
......
...@@ -46,14 +46,14 @@ def apply_color_correction(correction, image): ...@@ -46,14 +46,14 @@ def apply_color_correction(correction, image):
class StableDiffusionProcessing: class StableDiffusionProcessing:
def __init__(self, sd_model=None, outpath_samples=None, outpath_grids=None, prompt="", prompt_style="None", seed=-1, subseed=-1, subseed_strength=0, seed_resize_from_h=-1, seed_resize_from_w=-1, sampler_index=0, batch_size=1, n_iter=1, steps=50, cfg_scale=7.0, width=512, height=512, restore_faces=False, tiling=False, do_not_save_samples=False, do_not_save_grid=False, extra_generation_params=None, overlay_images=None, negative_prompt=None): def __init__(self, sd_model=None, outpath_samples=None, outpath_grids=None, prompt="", styles=None, seed=-1, subseed=-1, subseed_strength=0, seed_resize_from_h=-1, seed_resize_from_w=-1, sampler_index=0, batch_size=1, n_iter=1, steps=50, cfg_scale=7.0, width=512, height=512, restore_faces=False, tiling=False, do_not_save_samples=False, do_not_save_grid=False, extra_generation_params=None, overlay_images=None, negative_prompt=None):
self.sd_model = sd_model self.sd_model = sd_model
self.outpath_samples: str = outpath_samples self.outpath_samples: str = outpath_samples
self.outpath_grids: str = outpath_grids self.outpath_grids: str = outpath_grids
self.prompt: str = prompt self.prompt: str = prompt
self.prompt_for_display: str = None self.prompt_for_display: str = None
self.negative_prompt: str = (negative_prompt or "") self.negative_prompt: str = (negative_prompt or "")
self.prompt_style: str = prompt_style self.styles: str = styles
self.seed: int = seed self.seed: int = seed
self.subseed: int = subseed self.subseed: int = subseed
self.subseed_strength: float = subseed_strength self.subseed_strength: float = subseed_strength
...@@ -182,7 +182,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed: ...@@ -182,7 +182,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
comments = [] comments = []
modules.styles.apply_style(p, shared.prompt_styles[p.prompt_style]) shared.prompt_styles.apply_styles(p)
if type(p.prompt) == list: if type(p.prompt) == list:
all_prompts = p.prompt all_prompts = p.prompt
......
...@@ -81,7 +81,7 @@ state = State() ...@@ -81,7 +81,7 @@ state = State()
artist_db = modules.artists.ArtistsDatabase(os.path.join(script_path, 'artists.csv')) artist_db = modules.artists.ArtistsDatabase(os.path.join(script_path, 'artists.csv'))
styles_filename = cmd_opts.styles_file styles_filename = cmd_opts.styles_file
prompt_styles = modules.styles.load_styles(styles_filename) prompt_styles = modules.styles.StyleDatabase(styles_filename)
interrogator = modules.interrogate.InterrogateModels("interrogate") interrogator = modules.interrogate.InterrogateModels("interrogate")
......
...@@ -20,49 +20,67 @@ class PromptStyle(typing.NamedTuple): ...@@ -20,49 +20,67 @@ class PromptStyle(typing.NamedTuple):
negative_prompt: str negative_prompt: str
def load_styles(path: str) -> dict[str, PromptStyle]: def merge_prompts(style_prompt: str, prompt: str) -> str:
styles = {"None": PromptStyle("None", "", "")} if "{prompt}" in style_prompt:
res = style_prompt.replace("{prompt}", prompt)
else:
parts = filter(None, (prompt.strip(), style_prompt.strip()))
res = ", ".join(parts)
if os.path.exists(path): return res
with open(path, "r", encoding="utf8", newline='') as file:
reader = csv.DictReader(file)
for row in reader:
# Support loading old CSV format with "name, text"-columns
prompt = row["prompt"] if "prompt" in row else row["text"]
negative_prompt = row.get("negative_prompt", "")
styles[row["name"]] = PromptStyle(row["name"], prompt, negative_prompt)
return styles
def apply_styles_to_prompt(prompt, styles):
for style in styles:
prompt = merge_prompts(style, prompt)
def merge_prompts(style_prompt: str, prompt: str) -> str: return prompt
parts = filter(None, (prompt.strip(), style_prompt.strip()))
return ", ".join(parts)
def apply_style(processing: StableDiffusionProcessing, style: PromptStyle) -> None: class StyleDatabase:
if isinstance(processing.prompt, list): def __init__(self, path: str):
processing.prompt = [merge_prompts(style.prompt, p) for p in processing.prompt] self.no_style = PromptStyle("None", "", "")
else: self.styles = {"None": self.no_style}
processing.prompt = merge_prompts(style.prompt, processing.prompt)
if isinstance(processing.negative_prompt, list): if not os.path.exists(path):
processing.negative_prompt = [merge_prompts(style.negative_prompt, p) for p in processing.negative_prompt] return
else:
processing.negative_prompt = merge_prompts(style.negative_prompt, processing.negative_prompt) with open(path, "r", encoding="utf8", newline='') as file:
reader = csv.DictReader(file)
for row in reader:
def save_styles(path: str, styles: abc.Iterable[PromptStyle]) -> None: # Support loading old CSV format with "name, text"-columns
# Write to temporary file first, so we don't nuke the file if something goes wrong prompt = row["prompt"] if "prompt" in row else row["text"]
fd, temp_path = tempfile.mkstemp(".csv") negative_prompt = row.get("negative_prompt", "")
with os.fdopen(fd, "w", encoding="utf8", newline='') as file: self.styles[row["name"]] = PromptStyle(row["name"], prompt, negative_prompt)
# _fields is actually part of the public API: typing.NamedTuple is a replacement for collections.NamedTuple,
# and collections.NamedTuple has explicit documentation for accessing _fields. Same goes for _asdict() def apply_styles_to_prompt(self, prompt, styles):
writer = csv.DictWriter(file, fieldnames=PromptStyle._fields) return apply_styles_to_prompt(prompt, [self.styles.get(x, self.no_style).prompt for x in styles])
writer.writeheader()
writer.writerows(style._asdict() for style in styles) def apply_negative_styles_to_prompt(self, prompt, styles):
return apply_styles_to_prompt(prompt, [self.styles.get(x, self.no_style).negative_prompt for x in styles])
# Always keep a backup file around
if os.path.exists(path): def apply_styles(self, p: StableDiffusionProcessing) -> None:
shutil.move(path, path + ".bak") if isinstance(p.prompt, list):
shutil.move(temp_path, path) p.prompt = [self.apply_styles_to_prompt(prompt, p.styles) for prompt in p.prompt]
else:
p.prompt = self.apply_styles_to_prompt(p.prompt, p.styles)
if isinstance(p.negative_prompt, list):
p.negative_prompt = [self.apply_negative_styles_to_prompt(prompt, p.styles) for prompt in p.negative_prompt]
else:
p.negative_prompt = self.apply_negative_styles_to_prompt(p.negative_prompt, p.styles)
def save_styles(self, path: str) -> None:
# Write to temporary file first, so we don't nuke the file if something goes wrong
fd, temp_path = tempfile.mkstemp(".csv")
with os.fdopen(fd, "w", encoding="utf8", newline='') as file:
# _fields is actually part of the public API: typing.NamedTuple is a replacement for collections.NamedTuple,
# and collections.NamedTuple has explicit documentation for accessing _fields. Same goes for _asdict()
writer = csv.DictWriter(file, fieldnames=PromptStyle._fields)
writer.writeheader()
writer.writerows(style._asdict() for k, style in self.styles.items())
# Always keep a backup file around
if os.path.exists(path):
shutil.move(path, path + ".bak")
shutil.move(temp_path, path)
...@@ -6,13 +6,13 @@ import modules.processing as processing ...@@ -6,13 +6,13 @@ import modules.processing as processing
from modules.ui import plaintext_to_html from modules.ui import plaintext_to_html
def txt2img(prompt: str, negative_prompt: str, prompt_style: str, steps: int, sampler_index: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, height: int, width: int, *args): def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: str, steps: int, sampler_index: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, height: int, width: int, *args):
p = StableDiffusionProcessingTxt2Img( p = StableDiffusionProcessingTxt2Img(
sd_model=shared.sd_model, sd_model=shared.sd_model,
outpath_samples=opts.outdir_samples or opts.outdir_txt2img_samples, outpath_samples=opts.outdir_samples or opts.outdir_txt2img_samples,
outpath_grids=opts.outdir_grids or opts.outdir_txt2img_grids, outpath_grids=opts.outdir_grids or opts.outdir_txt2img_grids,
prompt=prompt, prompt=prompt,
prompt_style=prompt_style, styles=[prompt_style, prompt_style2],
negative_prompt=negative_prompt, negative_prompt=negative_prompt,
seed=seed, seed=seed,
subseed=subseed, subseed=subseed,
......
This diff is collapsed.
...@@ -60,6 +60,12 @@ titles = { ...@@ -60,6 +60,12 @@ titles = {
"Loopback": "Process an image, use it as an input, repeat.", "Loopback": "Process an image, use it as an input, repeat.",
"Loops": "How many times to repeat processing an image and using it as input for the next iteration", "Loops": "How many times to repeat processing an image and using it as input for the next iteration",
"Style 1": "Style to apply; styles have components for both positive and negative prompts and apply to both",
"Style 2": "Style to apply; styles have components for both positive and negative prompts and apply to both",
"Apply style": "Insert selected styles into prompt fields",
"Create style": "Save current prompts as a style. If you add the token {prompt} to the text, the style use that as placeholder for your prompt when you use the style in the future.",
} }
function gradioApp(){ function gradioApp(){
......
.output-html p {margin: 0 0.5em;} .output-html p {margin: 0 0.5em;}
.performance { font-size: 0.85em; color: #444; } .performance { font-size: 0.85em; color: #444; }
#txt2img_generate, #img2img_generate{ #generate{
max-width: 13em; min-height: 4.5em;
}
#img2img_interrogate{
max-width: 10em;
} }
#subseed_show{ #subseed_show{
...@@ -18,16 +14,27 @@ ...@@ -18,16 +14,27 @@
height: 100%; height: 100%;
} }
#txt2img_roll{ #roll{
min-width: 1em; min-width: 1em;
max-width: 4em; max-width: 4em;
margin: 0.5em;
}
#style_apply, #style_create, #interrogate{
margin: 0.75em 0.25em 0.25em 0.25em;
min-width: 3em;
}
#style_pos_col, #style_neg_col{
min-width: 4em !important;
}
#style_index, #style2_index{
margin-top: 1em;
} }
#style_index{ .gr-form{
min-width: 9em; background: transparent;
max-width: 9em;
padding-left: 0;
padding-right: 0;
} }
#toprow div{ #toprow div{
...@@ -43,10 +50,10 @@ button{ ...@@ -43,10 +50,10 @@ button{
align-self: stretch !important; align-self: stretch !important;
} }
#img2img_prompt, #txt2img_prompt, #img2img_negative_prompt, #txt2img_negative_prompt{ #prompt, #negative_prompt{
border: none !important; border: none !important;
} }
#img2img_prompt textarea, #txt2img_prompt textarea, #img2img_negative_prompt textarea, #txt2img_negative_prompt textarea{ #prompt textarea, #negative_prompt textarea{
border: none !important; border: none !important;
} }
...@@ -134,8 +141,6 @@ input[type="range"]{ ...@@ -134,8 +141,6 @@ input[type="range"]{
} }
#txt2img_negative_prompt, #img2img_negative_prompt{ #txt2img_negative_prompt, #img2img_negative_prompt{
flex: 0.3;
min-width: 10em;
} }
.progressDiv{ .progressDiv{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment