CoolFace
Apppublic

cymic/Waifu_Diffusion_Webui

sourceHugging Faceupdated 4y agoView on Hugging Face
1likes
styles.py93 linesDownload Raw Back to modules
1# We need this so Python doesn't complain about the unknown StableDiffusionProcessing-typehint at runtime2from __future__ import annotations3 4import csv5import os6import os.path7import typing8import collections.abc as abc9import tempfile10import shutil11 12if typing.TYPE_CHECKING:13    # Only import this when code is being type-checked, it doesn't have any effect at runtime14    from .processing import StableDiffusionProcessing15 16 17class PromptStyle(typing.NamedTuple):18    name: str19    prompt: str20    negative_prompt: str21 22 23def merge_prompts(style_prompt: str, prompt: str) -> str:24    if "{prompt}" in style_prompt:25        res = style_prompt.replace("{prompt}", prompt)26    else:27        parts = filter(None, (prompt.strip(), style_prompt.strip()))28        res = ", ".join(parts)29 30    return res31 32 33def apply_styles_to_prompt(prompt, styles):34    for style in styles:35        prompt = merge_prompts(style, prompt)36 37    return prompt38 39 40class StyleDatabase:41    def __init__(self, path: str):42        self.no_style = PromptStyle("None", "", "")43        self.styles = {"None": self.no_style}44 45        if not os.path.exists(path):46            return47 48        with open(path, "r", encoding="utf8", newline='') as file:49            reader = csv.DictReader(file)50            for row in reader:51                # Support loading old CSV format with "name, text"-columns52                prompt = row["prompt"] if "prompt" in row else row["text"]53                negative_prompt = row.get("negative_prompt", "")54                self.styles[row["name"]] = PromptStyle(row["name"], prompt, negative_prompt)55 56    def get_style_prompts(self, styles):57        return [self.styles.get(x, self.no_style).prompt for x in styles]58 59    def get_negative_style_prompts(self, styles):60        return [self.styles.get(x, self.no_style).negative_prompt for x in styles]61 62    def apply_styles_to_prompt(self, prompt, styles):63        return apply_styles_to_prompt(prompt, [self.styles.get(x, self.no_style).prompt for x in styles])64 65    def apply_negative_styles_to_prompt(self, prompt, styles):66        return apply_styles_to_prompt(prompt, [self.styles.get(x, self.no_style).negative_prompt for x in styles])67 68    def apply_styles(self, p: StableDiffusionProcessing) -> None:69        if isinstance(p.prompt, list):70            p.prompt = [self.apply_styles_to_prompt(prompt, p.styles) for prompt in p.prompt]71        else:72            p.prompt = self.apply_styles_to_prompt(p.prompt, p.styles)73 74        if isinstance(p.negative_prompt, list):75            p.negative_prompt = [self.apply_negative_styles_to_prompt(prompt, p.styles) for prompt in p.negative_prompt]76        else:77            p.negative_prompt = self.apply_negative_styles_to_prompt(p.negative_prompt, p.styles)78 79    def save_styles(self, path: str) -> None:80        # Write to temporary file first, so we don't nuke the file if something goes wrong81        fd, temp_path = tempfile.mkstemp(".csv")82        with os.fdopen(fd, "w", encoding="utf8", newline='') as file:83            # _fields is actually part of the public API: typing.NamedTuple is a replacement for collections.NamedTuple,84            # and collections.NamedTuple has explicit documentation for accessing _fields. Same goes for _asdict()85            writer = csv.DictWriter(file, fieldnames=PromptStyle._fields)86            writer.writeheader()87            writer.writerows(style._asdict() for k,     style in self.styles.items())88 89        # Always keep a backup file around90        if os.path.exists(path):91            shutil.move(path, path + ".bak")92        shutil.move(temp_path, path)93