diff --git a/README.md b/README.md index f3c3eec..c49d60f 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@
- +
## About The Project @@ -124,30 +124,22 @@ Run git clone to get the prompt-gallery. Make sure you cloned the [stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui) before. If not check out [stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui) to install it first. -You have two options now. :> +Follow instructions on [stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui) to start webui -Option A: +Goto Tab extensions in the webui and paste: -Manually copy prompt-gallery into stable-diffusion-webui. +1. paste https://github.com/dr413677671/PromptGallery-stable-diffusion-webui.git into textbox "URL for extension's git repository" -> copy ./PromptGallery-stable-diffusion-webui/prompt-gallery to stable-diffusion-webui-project-path/extensions +2. Set Prompt Gallery as "Local directory name" -> copy ./PromptGallery-stable-diffusion-webui/scripts/prompt_gallery.py to stable-diffusion-webui-project-path/scripts + ![install](./images/install.JPG) -Option B: - -> Alternatively, goto the cloned promptgallery-stable-diffusion-webui folder and run - - ```sh - python setup.py - ```

(back to top)

## Usage -Follow instructions on [stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui) to start webui View the video tutorial to use prompt-gallery: View Demo @@ -207,41 +199,41 @@ Teamplate: Select avatar (model for demo) -> Select prompt-sets -> Click "send WebUI" - ![2-1](./prompt-gallery/images/2-1.JPG) + ![2-1](./images/2-1.JPG) Checkout the downloaded Images - ![2-2](./prompt-gallery/images/2-2.JPG) + ![2-2](./images/2-2.JPG) ### Populate previews and QC For instance having added two prompt-sets, and we would like to add preview pictures for them. - ![3-1](./prompt-gallery/images/3-1.JPG) + ![3-1](./images/3-1.JPG) Goto tab "txt2img" and Select "Prompt Gallery" in tab "scripts" - ![3-2](./prompt-gallery/images/3-2.JPG) + ![3-2](./images/3-2.JPG) Upload yaml library of avatar first and select avatar. - ![3-3](./prompt-gallery/images/3-3.JPG) + ![3-3](./images/3-3.JPG) Add default prompts and upload prompt-set yaml library. - ![3-4](./prompt-gallery/images/3-4.JPG) + ![3-4](./images/3-4.JPG) Wait for stable-diffusion-webui generate previews automatically. - ![3-5](./prompt-gallery/images/3-5.JPG) + ![3-5](./images/3-5.JPG) Pick the best image for preview. - ![3-6](./prompt-gallery/images/3-6.JPG) + ![3-6](./images/3-6.JPG) Check it out in Prompt Gallery. - ![3-7](./prompt-gallery/images/3-7.JPG) + ![3-7](./images/3-7.JPG) You could always inspect you pictures manually in prompt-gallery-directory/assets/preview/ diff --git a/extensions/prompt-gallery/assets/avatars.yaml b/assets/avatars.yaml similarity index 100% rename from extensions/prompt-gallery/assets/avatars.yaml rename to assets/avatars.yaml diff --git a/extensions/prompt-gallery/assets/default.b2d19cd6.jpg b/assets/default.b2d19cd6.jpg similarity index 100% rename from extensions/prompt-gallery/assets/default.b2d19cd6.jpg rename to assets/default.b2d19cd6.jpg diff --git a/extensions/prompt-gallery/assets/default.jpg b/assets/default.jpg similarity index 100% rename from extensions/prompt-gallery/assets/default.jpg rename to assets/default.jpg diff --git a/extensions/prompt-gallery/assets/index.78a31c12.css b/assets/index.78a31c12.css similarity index 100% rename from extensions/prompt-gallery/assets/index.78a31c12.css rename to assets/index.78a31c12.css diff --git a/extensions/prompt-gallery/assets/index.d8193a82.js b/assets/index.d8193a82.js similarity index 100% rename from extensions/prompt-gallery/assets/index.d8193a82.js rename to assets/index.d8193a82.js diff --git a/extensions/prompt-gallery/assets/tags.yaml b/assets/tags.yaml similarity index 100% rename from extensions/prompt-gallery/assets/tags.yaml rename to assets/tags.yaml diff --git a/extensions/prompt-gallery/.gitignore b/extensions/prompt-gallery/.gitignore deleted file mode 100644 index 72bb0da..0000000 --- a/extensions/prompt-gallery/.gitignore +++ /dev/null @@ -1 +0,0 @@ -path_recorder.txt diff --git a/extensions/prompt-gallery/scripts/prompt_gallery.py b/extensions/prompt-gallery/scripts/prompt_gallery.py deleted file mode 100644 index 9a6b472..0000000 --- a/extensions/prompt-gallery/scripts/prompt_gallery.py +++ /dev/null @@ -1,55 +0,0 @@ -import os -import shutil -import time -import stat -import gradio as gr -import modules.extras -import modules.ui -from modules.shared import opts, cmd_opts -from modules import shared, scripts -from modules import script_callbacks -from pathlib import Path -from typing import List, Tuple -import uvicorn -from uvicorn import Config -from fastapi import FastAPI -from fastapi.staticfiles import StaticFiles -import contextlib -import threading -import requests -from fastapi.middleware.cors import CORSMiddleware - - -def on_ui_settings(): - app = FastAPI() - app.mount('/', StaticFiles(directory='./extensions/prompt-gallery',html=True)) - config = Config(app=app, host='localhost',port=5173, log_level="info", loop="asyncio", limit_max_requests=1) - app.add_middleware( - CORSMiddleware, - allow_origins=["*"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"] - ) - - thread = threading.Thread(target= uvicorn.run, kwargs={'app':app, 'host': 'localhost', 'port':5173}) - thread.start() - tmp = requests.get("http://localhost:5173") - while tmp.status_code != 204 and tmp.status_code != 200: - time.sleep(0.01) - tmp = requests.get("http://localhost:5173") - pass - # thread.join() - - - -def on_ui_tabs(): - html = """""" - with gr.Blocks(analytics_enabled=False, elem_id="prompt_gallery") as prompt_gallery: - prompt_gallery = gr.HTML(html) - - return (prompt_gallery , "Prompt Gallery", "prompt_gallery"), - -script_callbacks.on_ui_tabs(on_ui_tabs) - -script_callbacks.on_ui_settings(on_ui_settings) \ No newline at end of file diff --git a/images/install.JPG b/images/install.JPG new file mode 100644 index 0000000..7353f7f Binary files /dev/null and b/images/install.JPG differ diff --git a/extensions/prompt-gallery/index.html b/index.html similarity index 100% rename from extensions/prompt-gallery/index.html rename to index.html diff --git a/install.py b/install.py new file mode 100644 index 0000000..1f2f7b5 --- /dev/null +++ b/install.py @@ -0,0 +1,15 @@ +import os +import shutil +import json +import launch + + +if not launch.is_installed("pyyaml"): + launch.run_pip("install pyyaml", "requirements for Prompt Gallery") + +current_dir= os.path.abspath(os.path.dirname(__file__)) +trg = os.path.join(os.path.join(os.path.join(current_dir, os.path.pardir), os.path.pardir), "scripts/prompt_gallery.py") +shutil.copyfile(os.path.join(os.path.join(current_dir,"paste_this_to_webui_scripts_folder"),"prompt_gallery.py"), trg) +name = os.path.basename(current_dir) +with open(os.path.join(current_dir, os.path.join(os.path.join(current_dir, os.path.pardir), "prompt_gallery_name.json")), 'w') as fd: + json.dump({'name': name}, fd) diff --git a/paste_this_to_webui_scripts_folder/prompt_gallery.py b/paste_this_to_webui_scripts_folder/prompt_gallery.py new file mode 100644 index 0000000..7f0e7a7 --- /dev/null +++ b/paste_this_to_webui_scripts_folder/prompt_gallery.py @@ -0,0 +1,585 @@ +import copy +import os +import random +import sys +import traceback +import shlex +import yaml +import platform +import subprocess as sp +import shutil +import tempfile +import gradio as gr +import csv +import typing +import base64 +import io +from PIL import Image +import mimetypes +mimetypes.init() +mimetypes.add_type('application/javascript', '.js') + +import modules.generation_parameters_copypaste as parameters_copypaste +from modules.generation_parameters_copypaste import image_from_url_text +import modules.scripts as scripts +from modules.processing import Processed, process_images + +from modules.shared import opts, cmd_opts, state +import modules.shared as shared + +if '__file__' in locals().keys(): + root_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + root_path = os.path.join(root_path, "../") +else: + if platform.system() == "Windows": + root_path = "./" + else: + root_path = "./" + +# OUTPATH_SAMPLES = root_path + "/outputs/preview_outputs/preview/" +# OUTPATH_GRIDS = root_path + "/outputs/preview_outputs/grid/" +OUTPATH_SAMPLES = './extensions/prompt-gallery/assets/preview/' +OUTPATH_GRIDS = './extensions/prompt-gallery/assets/grid/' + +BATCH_SIZE = 4 +N_ITER = 2 +STEPS = 30 +CFG_SCALE = 11.5 +WIDTH = 512 +HEIGHT = 768 +SAMPLER_INDEX = 1 +RESTORE_FACE = 'true' +TILING = 'false' +DO_NOT_SAVE_GRID = 'false' +SD_MODEL = '925997e9' + +EXCLUDED_TAGS = [''] +global SKIP_EXISTS +SKIP_EXISTS = True + +OUTPUTS_DICT = list() +OUTPUTS = {} +rawDict = {} +qc_dict = {} +trg_img = '' +current_folder = '' + +map_sampler_to_idx = { + 'Euler a': 0, + 'Euler': 1, + 'LMS': 2, + 'Heun': 3, + 'DPM2': 4, + 'DPM2 a': 5, + 'DPM fast': 6, + 'DPM adaptive': 7, + 'LMS Karras': 8, + 'DPM2 Karras': 9, + 'DPM2 a Karras': 10, + 'DDIM': 11, + 'PLMS': 12} + +map_keys = { + "value": "prompt", + "negative": "negative_prompt"} + +map_param = { + "sd_model": "sd_model", + "outpath_samples": "outpath_samples", + "outpath_grids": "outpath_grids", + "prompt_for_display": "prompt_for_display", + "styles": "styles", + "Seed": "seed", + "Variation seed strength": "subseed_strength", + "Variation seed": "subseed", + "seed_resize_from_h": "seed_resize_from_h", + "seed_resize_from_w": "seed_resize_from_w", + "Sampler": "sampler_index", + "batch_size": "batch_size", + "n_iter": "n_iter", + "Steps": "steps", + "CFG scale": "cfg_scale", + "width": "width", + "height": "height", + "restore_faces": "restore_faces", + "tiling": "tiling", + "do_not_save_samples": "do_not_save_samples", + "do_not_save_grid": "do_not_save_grid"} + +def process_string_tag(tag): + return tag + + +def process_int_tag(tag): + return int(tag) + + +def process_float_tag(tag): + return float(tag) + + +def process_boolean_tag(tag): + return True if (tag == "true") else False + + +prompt_tags = { + "sd_model": None, + "outpath_samples": process_string_tag, + "outpath_grids": process_string_tag, + "prompt_for_display": process_string_tag, + "prompt": process_string_tag, + "negative_prompt": process_string_tag, + "styles": process_string_tag, + "seed": process_int_tag, + "subseed_strength": process_float_tag, + "subseed": process_int_tag, + "seed_resize_from_h": process_int_tag, + "seed_resize_from_w": process_int_tag, + "sampler_index": process_int_tag, + "batch_size": process_int_tag, + "n_iter": process_int_tag, + "steps": process_int_tag, + "cfg_scale": process_float_tag, + "width": process_int_tag, + "height": process_int_tag, + "restore_faces": process_boolean_tag, + "tiling": process_boolean_tag, + "do_not_save_samples": process_boolean_tag, + "do_not_save_grid": process_boolean_tag +} + +avatar_prompts = list() +avatar_names = list() +avatar_negatives = list() +avatar_name = "" + +def cmdargs(line): + args = shlex.split(line) + pos = 0 + res = {} + + while pos < len(args): + arg = args[pos] + + assert arg.startswith("--"), f'must start with "--": {arg}' + tag = arg[2:] + + func = prompt_tags.get(tag, None) + assert func, f'unknown commandline option: {arg}' + + assert pos+1 < len(args), f'missing argument for command line option {arg}' + + val = args[pos+1] + + res[tag] = func(val) + + pos += 2 + + return res + + + +def add_param(key, value, cur_str): + cur_str += '--{key} {value} '.format(key=key, value=value) + return cur_str + +def parse_size(i_width, i_height, str_size, cur_str): + i_width = str_size.split('x')[0] + i_height = str_size.split('x')[1] + +def parse_virariant_size(str_size, cur_str): + width = str_size.split('x')[0] + height = str_size.split('x')[1] + cur_str = add_param('seed_resize_from_w', width, cur_str) + cur_str = add_param('seed_resize_from_h', height, cur_str) + return cur_str + +def parse_param(param_str): + m_batch_size = BATCH_SIZE + m_n_iter = N_ITER + m_steps = STEPS + m_cfg_scale = CFG_SCALE + m_width = WIDTH + m_height = HEIGHT + m_sampler_index = SAMPLER_INDEX + # m_tiling = TILING + m_restore_faces = RESTORE_FACE + m_do_not_save_grid = DO_NOT_SAVE_GRID + # m_sd_model = sd_model + cur_line = "" + for item in param_str.split(', '): + if item == '': + continue + group = item.split(': ') + key = group[0] + value = group[1] + if key == 'Steps': + m_steps = value + elif key == "CFG scale": + m_cfg_scale = value + elif value == 'Sampler': + m_sampler_index = map_sampler_to_idx[value] + elif key == 'Size': + parse_size(m_width, m_height, value, cur_line) + elif key == 'Seed resize from': + cur_line = parse_virariant_size(value, cur_line) + elif key == 'Seed': + cur_line = add_param("seed", value, cur_line) + elif key == 'Variation seed strength': + cur_line = add_param("subseed_strength", value, cur_line) + elif key == 'Variation seed': + cur_line = add_param("subseed", value, cur_line) + # elif key == 'Model hash': + # cur_line = add_param("sd_model", m_sd_model, cur_line) + cur_line = add_param("batch_size", m_batch_size, cur_line) + cur_line = add_param("n_iter", m_n_iter, cur_line) + cur_line = add_param("steps", m_steps, cur_line) + cur_line = add_param("cfg_scale", m_cfg_scale, cur_line) + cur_line = add_param("sampler_index", m_sampler_index, cur_line) + cur_line = add_param("width", m_width, cur_line) + cur_line = add_param("height", m_height, cur_line) + cur_line = add_param("restore_faces", m_restore_faces, cur_line) +# cur_line = add_param("tiling", m_tiling, cur_line) + cur_line = add_param("do_not_save_grid", m_do_not_save_grid, cur_line) + return cur_line + +def parse_yaml_dict(rawDict, tag, avatar_prompt, avatar_name, default_negative): + # depth-first-search + if 'value' in rawDict.keys() or 'negative' in rawDict.keys(): + if SKIP_EXISTS: + if os.path.exists(OUTPATH_SAMPLES + tag + '/' + avatar_name+'.png') or os.path.exists(OUTPATH_SAMPLES + tag + '\\' + 'Not-available.png'): + print("Skip "+str(tag)) + return "" + cur = "" + parsed_param = False + m_positive = avatar_prompt + m_negative = default_negative + for item in rawDict.items(): + key = item[0] + value = item[1] + if key == 'param': + params = parse_param(rawDict['param']) + parsed_param = True + elif key == 'value': + m_positive = value + m_positive + elif key == 'negative': + m_negative = value +','+ m_negative + + cur += "--{key} \"{value}\" ".format(key='prompt', value= m_positive) + cur += "--{key} \"{value}\" ".format(key='negative_prompt', value= m_negative) + + if parsed_param == False: + params = parse_param("") + cur += params + cur = add_param('outpath_samples', '\"'+OUTPATH_SAMPLES + str(tag)+'\"', cur) + cur = add_param('outpath_grids', '\"'+OUTPATH_GRIDS + str(tag)+'\"', cur) + return cur + else: + for item in rawDict.items(): + key = item[0] + ret = parse_yaml_dict(rawDict[key], tag if key=='' else key, avatar_prompt, avatar_name, default_negative) + if len(ret) != 0: + if tag not in EXCLUDED_TAGS: + OUTPUTS_DICT.append({'name': key, + 'prompt': item[1]['value'] if 'value' in item[1].keys() else '', + 'negative_prompt': item[1]['negative'] if 'negative' in item[1].keys() else ''}) + if tag in OUTPUTS.keys(): + OUTPUTS[tag].append(ret) + else: + OUTPUTS[tag] = [ret] + return "" + + +def rename_preview(avatar_name): + if avatar_name == '': + print("Please select avatar name first.") + return + root = OUTPATH_SAMPLES + for folder in os.listdir(root): + files = os.listdir(root + folder) + if 'Not-available.png' in files: + print('Skip '+ folder + ' not available.') + continue + if avatar_name + '.png' in files: + continue + for each_avatar in avatar_names: + if each_avatar + '.png' in files: + files.remove(each_avatar + '.png') + if len(files) == 1: + os.rename(root + folder + '/' + files[0], root + folder + '/' + avatar_name + '.png') + else: + print('There are 0 or more than 1 files in ' + folder) + +def load_prompt_file(file): + if (file is None): + lines = [] + else: + lines = [x.strip() for x in file.decode('utf8', errors='ignore').split("\n")] + + return None, "\n".join(lines), gr.update(lines=7) + +def copy_from_prompt_app(): + return [] + +def open_folder(f): + if not os.path.exists(f): + print(f'Folder "{f}" does not exist. After you create an image, the folder will be created.') + return + elif not os.path.isdir(f): + print(f""" +WARNING +An open_folder request was made with an argument that is not a folder. +This could be an error or a malicious attempt to run code on your computer. +Requested path was: {f} +""", file=sys.stderr) + return + + if not shared.cmd_opts.hide_ui_dir_config: + path = os.path.normpath(f) + if platform.system() == "Windows": + os.startfile(path) + elif platform.system() == "Darwin": + sp.Popen(["open", path]) + else: + sp.Popen(["xdg-open", path]) + +class PromptStyle(typing.NamedTuple): + name: str + prompt: str + negative_prompt: str + +def save_styles() -> None: + if len(OUTPUTS.keys()) == 0: + return + path = root_path + '/styles.csv' + # 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="utf-8-sig", 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() + for row in OUTPUTS_DICT: + writer.writerow({'name': row['name'], 'prompt': row['prompt'], 'negative_prompt': row['negative_prompt']}) + # 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) + +def load_prompt(file, default_negative, dropdown, skip_exist): + global SKIP_EXISTS + SKIP_EXISTS = skip_exist + if dropdown == '': + return + rawDict = yaml.load(file, Loader = yaml.BaseLoader) + default_negative = default_negative + ',' + avatar_negatives[avatar_names.index(dropdown)] + parse_yaml_dict(rawDict, "", avatar_prompts[avatar_names.index(dropdown)], dropdown, default_negative) + prompt_txt = "" + keys = list(filter(lambda x: x not in EXCLUDED_TAGS, OUTPUTS.keys())) + for style in keys: + for each_line in OUTPUTS[style]: + prompt_txt += each_line + '\n' + return [prompt_txt, gr.Row.update(visible=True)] + +def load_avartar(avatar_dict, customize_tags_positive): + avatars = yaml.load(avatar_dict, yaml.BaseLoader) + + for name, prompt in avatars.items(): + avatar_names.append(name) + if 'value' in prompt.keys(): + avatar_prompts.append(customize_tags_positive + ', ' + prompt['value']) + if 'negative' in prompt.keys(): + avatar_negatives.append(prompt['negative']) + return [gr.Dropdown.update(choices=avatar_names, value=avatar_names[0]), gr.Column.update(visible=True), gr.Group.update(visible=True)] + +def scan_outputs(avatar_name): + if avatar_name is None or len(avatar_name) == 0: + print("Please select avatar name first.") + return + root = OUTPATH_SAMPLES + global qc_dict + qc_dict = {} + for folder in os.listdir(root): + if os.path.isdir(root + folder) == False: + continue + + files = os.listdir(root + folder) + if 'Not-available.png' in files: + print('Skip '+ folder + ' not available.') + continue + if avatar_name + '.png' in files: + continue + for each_avatar in avatar_names: + if each_avatar + '.png' in files: + files.remove(each_avatar + '.png') + if len(files) == 0: + continue + qc_dict[folder] = [root + folder + '/' + file for file in files] + + if len(qc_dict.keys()) == 0: + return gr.Dropdown.update(choices=[]) + return gr.Dropdown.update(choices=list(qc_dict.keys()), value=list(qc_dict.keys())[0]) + +def update_gallery(dropdown, avatar): + root = OUTPATH_SAMPLES + global trg_img, current_folder + current_folder = root + dropdown + trg_img = root + dropdown + '/' + avatar + '.png' + return qc_dict[dropdown] + +def clean_select_picture(filename): + if current_folder == '': + print("Please select qc tag.") + return + for file in os.listdir(current_folder): + is_avatar = False + for each_avatar in avatar_names: + if each_avatar + '.png' == file: + is_avatar = True + break + if os.path.splitext(file)[0] in filename: + os.rename(current_folder+'/'+file, trg_img) + elif is_avatar == False: + os.remove(current_folder+'/'+file) + +def image_url(filedata): + if type(filedata) == dict and filedata["is_file"]: + filename = filedata["name"] + tempdir = os.path.normpath(tempfile.gettempdir()) + normfn = os.path.normpath(filename) + assert normfn.startswith(tempdir), 'trying to open image file not in temporary directory' + + image = Image.open(filename) + clean_select_picture(os.path.basename(filename)) + return Image.open(filename) + + if type(filedata) == list: + if len(filedata) == 0: + return None + + filedata = filedata[0] + + if filedata.startswith("data:image/png;base64,"): + filedata = filedata[len("data:image/png;base64,"):] + + filedata = base64.decodebytes(filedata.encode('utf-8')) + image = Image.open(io.BytesIO(filedata)) + return image + + + + + +class Script(scripts.Script): + def title(self): + return "Prompt gallery" + + def ui(self, is_img2img): + with gr.Group(): + with gr.Column(): + label_avatar = gr.Label("Upload avatars config") + avatar_dict = gr.File(label="Upload avatar prompt inputs", type='bytes') + + # copy_from_app_button = gr.Button("Copy From Prompt Preview") + + with gr.Group(): + with gr.Column(visible=False) as avatar_col: + label_presets = gr.Label("Presets") + dropdown = gr.Dropdown(label="Choose avatar", choices=[""], value="", type="value", elem_id="dropdown") + dropdown.save_to_config = True + with gr.Row(): + checkbox_iterate = gr.Checkbox(label="Iterate seed every line", value=False) + skip_exist = gr.Checkbox(value=True, label="skip exist") + default_negative = gr.Textbox(label="default_negative", lines=1) + default_positive = gr.Textbox(label="default_positive", lines=1) + prompt_dict = gr.File(label="Upload prompt dictionary", type='bytes') + with gr.Row(visible = False) as save_prompts: + open_button = gr.Button("Open outputs directory") + export_button = gr.Button("Export to WebUI style") + prompt_display = gr.Textbox(label="List of prompt inputs", lines=1) + + + prompt_dict.change(fn=load_prompt, inputs=[prompt_dict, default_negative, dropdown, skip_exist], outputs=[prompt_display, save_prompts]) + open_button.click(fn=lambda: open_folder(OUTPATH_SAMPLES), inputs=[], outputs=[]) + export_button.click(fn=save_styles, inputs=[], outputs=[]) + + with gr.Group(visible=False) as qc_widgets: + label_preview = gr.Label("QC preview") + with gr.Row(): + qc_refresh = gr.Button("QC scan") + preview_dropdown = gr.Dropdown(label="Select prompts", choices=[""], value="", type="value", elem_id="dropdown") + preview_gallery = gr.Gallery(label='Output', show_label=False, elem_id=f"preview_gallery").style(grid=4) + qc_refresh.click(fn=scan_outputs, inputs=[dropdown], outputs=preview_dropdown) + with gr.Row(): + qc_show = gr.Button(f"Show pics") + qc_select = gr.Button(f"Select") + rename_button = gr.Button("Auto rename") + selected_img = gr.Image(label="Selected",show_label=False, source="upload", interactive=True, type="pil").style(height=480) + qc_show.click(fn=update_gallery, inputs=[preview_dropdown, dropdown], outputs=preview_gallery) + qc_select.click( + fn=lambda x: image_url(x), + _js="extract_image_from_gallery", + inputs=[preview_gallery], + outputs=[selected_img], + ) + # qc_select.click(fn=select_picture, inputs=[dropdown, preview_dropdown, preview_gallery], outputs=[]) + rename_button.click(fn=rename_preview, inputs=[dropdown], outputs=[]) + # qc_select.click(fn=scan_outputs, inputs=[], outputs=[preview_dropdown]) + + avatar_dict.change(fn=load_avartar, inputs=[avatar_dict, default_positive], outputs=[dropdown, avatar_col, qc_widgets]) + return [checkbox_iterate, avatar_dict, prompt_dict, default_negative, default_positive, dropdown, prompt_display, rename_button, label_avatar, open_button, export_button, skip_exist, label_presets, label_preview, preview_dropdown, preview_gallery, qc_select, qc_refresh, qc_show, selected_img] + + def run(self, p, checkbox_iterate, avatar_dict, prompt_dict, default_negative, default_positive, dropdown, prompt_display, rename_button, label_avatar, open_button, export_button, skip_exist, label_presets, label_preview, preview_dropdown, preview_gallery, qc_select, qc_refresh, qc_show, selected_img): + lines = [x.strip() for x in prompt_display.splitlines()] + lines = [x for x in lines if len(x) > 0] + + p.do_not_save_grid = True + + job_count = 0 + jobs = [] + + for line in lines: + if "--" in line: + try: + args = cmdargs(line) + except Exception: + print(f"Error parsing line [line] as commandline:", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) + args = {"prompt": line} + else: + args = {"prompt": line} + + n_iter = args.get("n_iter", 1) + if n_iter != 1: + job_count += n_iter + else: + job_count += 1 + + jobs.append(args) + + print(f"Will process {len(lines)} lines in {job_count} jobs.") + if (checkbox_iterate and p.seed == -1): + p.seed = int(random.randrange(4294967294)) + + state.job_count = job_count + + images = [] + for n, args in enumerate(jobs): + state.job = f"{state.job_no + 1} out of {state.job_count}" + + copy_p = copy.copy(p) + for k, v in args.items(): + setattr(copy_p, k, v) + + proc = process_images(copy_p) + images += proc.images + + if (checkbox_iterate): + p.seed = p.seed + (p.batch_size * p.n_iter) + + OUTPUTS = {} + rawDict = {} + + return Processed(p, images, p.seed, "") \ No newline at end of file diff --git a/extensions/prompt-gallery/requirements.txt b/requirements.txt similarity index 100% rename from extensions/prompt-gallery/requirements.txt rename to requirements.txt diff --git a/scripts/prompt_gallery.py b/scripts/prompt_gallery.py index 7f0e7a7..75294aa 100644 --- a/scripts/prompt_gallery.py +++ b/scripts/prompt_gallery.py @@ -1,585 +1,57 @@ -import copy import os -import random -import sys -import traceback -import shlex -import yaml -import platform -import subprocess as sp import shutil -import tempfile +import time +import stat import gradio as gr -import csv -import typing -import base64 -import io -from PIL import Image -import mimetypes -mimetypes.init() -mimetypes.add_type('application/javascript', '.js') - -import modules.generation_parameters_copypaste as parameters_copypaste -from modules.generation_parameters_copypaste import image_from_url_text -import modules.scripts as scripts -from modules.processing import Processed, process_images - -from modules.shared import opts, cmd_opts, state -import modules.shared as shared - -if '__file__' in locals().keys(): - root_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) - root_path = os.path.join(root_path, "../") -else: - if platform.system() == "Windows": - root_path = "./" - else: - root_path = "./" - -# OUTPATH_SAMPLES = root_path + "/outputs/preview_outputs/preview/" -# OUTPATH_GRIDS = root_path + "/outputs/preview_outputs/grid/" -OUTPATH_SAMPLES = './extensions/prompt-gallery/assets/preview/' -OUTPATH_GRIDS = './extensions/prompt-gallery/assets/grid/' - -BATCH_SIZE = 4 -N_ITER = 2 -STEPS = 30 -CFG_SCALE = 11.5 -WIDTH = 512 -HEIGHT = 768 -SAMPLER_INDEX = 1 -RESTORE_FACE = 'true' -TILING = 'false' -DO_NOT_SAVE_GRID = 'false' -SD_MODEL = '925997e9' - -EXCLUDED_TAGS = [''] -global SKIP_EXISTS -SKIP_EXISTS = True - -OUTPUTS_DICT = list() -OUTPUTS = {} -rawDict = {} -qc_dict = {} -trg_img = '' -current_folder = '' - -map_sampler_to_idx = { - 'Euler a': 0, - 'Euler': 1, - 'LMS': 2, - 'Heun': 3, - 'DPM2': 4, - 'DPM2 a': 5, - 'DPM fast': 6, - 'DPM adaptive': 7, - 'LMS Karras': 8, - 'DPM2 Karras': 9, - 'DPM2 a Karras': 10, - 'DDIM': 11, - 'PLMS': 12} - -map_keys = { - "value": "prompt", - "negative": "negative_prompt"} - -map_param = { - "sd_model": "sd_model", - "outpath_samples": "outpath_samples", - "outpath_grids": "outpath_grids", - "prompt_for_display": "prompt_for_display", - "styles": "styles", - "Seed": "seed", - "Variation seed strength": "subseed_strength", - "Variation seed": "subseed", - "seed_resize_from_h": "seed_resize_from_h", - "seed_resize_from_w": "seed_resize_from_w", - "Sampler": "sampler_index", - "batch_size": "batch_size", - "n_iter": "n_iter", - "Steps": "steps", - "CFG scale": "cfg_scale", - "width": "width", - "height": "height", - "restore_faces": "restore_faces", - "tiling": "tiling", - "do_not_save_samples": "do_not_save_samples", - "do_not_save_grid": "do_not_save_grid"} - -def process_string_tag(tag): - return tag - - -def process_int_tag(tag): - return int(tag) - - -def process_float_tag(tag): - return float(tag) - - -def process_boolean_tag(tag): - return True if (tag == "true") else False - - -prompt_tags = { - "sd_model": None, - "outpath_samples": process_string_tag, - "outpath_grids": process_string_tag, - "prompt_for_display": process_string_tag, - "prompt": process_string_tag, - "negative_prompt": process_string_tag, - "styles": process_string_tag, - "seed": process_int_tag, - "subseed_strength": process_float_tag, - "subseed": process_int_tag, - "seed_resize_from_h": process_int_tag, - "seed_resize_from_w": process_int_tag, - "sampler_index": process_int_tag, - "batch_size": process_int_tag, - "n_iter": process_int_tag, - "steps": process_int_tag, - "cfg_scale": process_float_tag, - "width": process_int_tag, - "height": process_int_tag, - "restore_faces": process_boolean_tag, - "tiling": process_boolean_tag, - "do_not_save_samples": process_boolean_tag, - "do_not_save_grid": process_boolean_tag -} - -avatar_prompts = list() -avatar_names = list() -avatar_negatives = list() -avatar_name = "" - -def cmdargs(line): - args = shlex.split(line) - pos = 0 - res = {} - - while pos < len(args): - arg = args[pos] - - assert arg.startswith("--"), f'must start with "--": {arg}' - tag = arg[2:] - - func = prompt_tags.get(tag, None) - assert func, f'unknown commandline option: {arg}' - - assert pos+1 < len(args), f'missing argument for command line option {arg}' - - val = args[pos+1] - - res[tag] = func(val) - - pos += 2 - - return res - - - -def add_param(key, value, cur_str): - cur_str += '--{key} {value} '.format(key=key, value=value) - return cur_str - -def parse_size(i_width, i_height, str_size, cur_str): - i_width = str_size.split('x')[0] - i_height = str_size.split('x')[1] - -def parse_virariant_size(str_size, cur_str): - width = str_size.split('x')[0] - height = str_size.split('x')[1] - cur_str = add_param('seed_resize_from_w', width, cur_str) - cur_str = add_param('seed_resize_from_h', height, cur_str) - return cur_str - -def parse_param(param_str): - m_batch_size = BATCH_SIZE - m_n_iter = N_ITER - m_steps = STEPS - m_cfg_scale = CFG_SCALE - m_width = WIDTH - m_height = HEIGHT - m_sampler_index = SAMPLER_INDEX - # m_tiling = TILING - m_restore_faces = RESTORE_FACE - m_do_not_save_grid = DO_NOT_SAVE_GRID - # m_sd_model = sd_model - cur_line = "" - for item in param_str.split(', '): - if item == '': - continue - group = item.split(': ') - key = group[0] - value = group[1] - if key == 'Steps': - m_steps = value - elif key == "CFG scale": - m_cfg_scale = value - elif value == 'Sampler': - m_sampler_index = map_sampler_to_idx[value] - elif key == 'Size': - parse_size(m_width, m_height, value, cur_line) - elif key == 'Seed resize from': - cur_line = parse_virariant_size(value, cur_line) - elif key == 'Seed': - cur_line = add_param("seed", value, cur_line) - elif key == 'Variation seed strength': - cur_line = add_param("subseed_strength", value, cur_line) - elif key == 'Variation seed': - cur_line = add_param("subseed", value, cur_line) - # elif key == 'Model hash': - # cur_line = add_param("sd_model", m_sd_model, cur_line) - cur_line = add_param("batch_size", m_batch_size, cur_line) - cur_line = add_param("n_iter", m_n_iter, cur_line) - cur_line = add_param("steps", m_steps, cur_line) - cur_line = add_param("cfg_scale", m_cfg_scale, cur_line) - cur_line = add_param("sampler_index", m_sampler_index, cur_line) - cur_line = add_param("width", m_width, cur_line) - cur_line = add_param("height", m_height, cur_line) - cur_line = add_param("restore_faces", m_restore_faces, cur_line) -# cur_line = add_param("tiling", m_tiling, cur_line) - cur_line = add_param("do_not_save_grid", m_do_not_save_grid, cur_line) - return cur_line - -def parse_yaml_dict(rawDict, tag, avatar_prompt, avatar_name, default_negative): - # depth-first-search - if 'value' in rawDict.keys() or 'negative' in rawDict.keys(): - if SKIP_EXISTS: - if os.path.exists(OUTPATH_SAMPLES + tag + '/' + avatar_name+'.png') or os.path.exists(OUTPATH_SAMPLES + tag + '\\' + 'Not-available.png'): - print("Skip "+str(tag)) - return "" - cur = "" - parsed_param = False - m_positive = avatar_prompt - m_negative = default_negative - for item in rawDict.items(): - key = item[0] - value = item[1] - if key == 'param': - params = parse_param(rawDict['param']) - parsed_param = True - elif key == 'value': - m_positive = value + m_positive - elif key == 'negative': - m_negative = value +','+ m_negative - - cur += "--{key} \"{value}\" ".format(key='prompt', value= m_positive) - cur += "--{key} \"{value}\" ".format(key='negative_prompt', value= m_negative) - - if parsed_param == False: - params = parse_param("") - cur += params - cur = add_param('outpath_samples', '\"'+OUTPATH_SAMPLES + str(tag)+'\"', cur) - cur = add_param('outpath_grids', '\"'+OUTPATH_GRIDS + str(tag)+'\"', cur) - return cur - else: - for item in rawDict.items(): - key = item[0] - ret = parse_yaml_dict(rawDict[key], tag if key=='' else key, avatar_prompt, avatar_name, default_negative) - if len(ret) != 0: - if tag not in EXCLUDED_TAGS: - OUTPUTS_DICT.append({'name': key, - 'prompt': item[1]['value'] if 'value' in item[1].keys() else '', - 'negative_prompt': item[1]['negative'] if 'negative' in item[1].keys() else ''}) - if tag in OUTPUTS.keys(): - OUTPUTS[tag].append(ret) - else: - OUTPUTS[tag] = [ret] - return "" - - -def rename_preview(avatar_name): - if avatar_name == '': - print("Please select avatar name first.") - return - root = OUTPATH_SAMPLES - for folder in os.listdir(root): - files = os.listdir(root + folder) - if 'Not-available.png' in files: - print('Skip '+ folder + ' not available.') - continue - if avatar_name + '.png' in files: - continue - for each_avatar in avatar_names: - if each_avatar + '.png' in files: - files.remove(each_avatar + '.png') - if len(files) == 1: - os.rename(root + folder + '/' + files[0], root + folder + '/' + avatar_name + '.png') - else: - print('There are 0 or more than 1 files in ' + folder) - -def load_prompt_file(file): - if (file is None): - lines = [] - else: - lines = [x.strip() for x in file.decode('utf8', errors='ignore').split("\n")] - - return None, "\n".join(lines), gr.update(lines=7) - -def copy_from_prompt_app(): - return [] - -def open_folder(f): - if not os.path.exists(f): - print(f'Folder "{f}" does not exist. After you create an image, the folder will be created.') - return - elif not os.path.isdir(f): - print(f""" -WARNING -An open_folder request was made with an argument that is not a folder. -This could be an error or a malicious attempt to run code on your computer. -Requested path was: {f} -""", file=sys.stderr) - return - - if not shared.cmd_opts.hide_ui_dir_config: - path = os.path.normpath(f) - if platform.system() == "Windows": - os.startfile(path) - elif platform.system() == "Darwin": - sp.Popen(["open", path]) - else: - sp.Popen(["xdg-open", path]) - -class PromptStyle(typing.NamedTuple): - name: str - prompt: str - negative_prompt: str - -def save_styles() -> None: - if len(OUTPUTS.keys()) == 0: - return - path = root_path + '/styles.csv' - # 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="utf-8-sig", 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() - for row in OUTPUTS_DICT: - writer.writerow({'name': row['name'], 'prompt': row['prompt'], 'negative_prompt': row['negative_prompt']}) - # 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) - -def load_prompt(file, default_negative, dropdown, skip_exist): - global SKIP_EXISTS - SKIP_EXISTS = skip_exist - if dropdown == '': - return - rawDict = yaml.load(file, Loader = yaml.BaseLoader) - default_negative = default_negative + ',' + avatar_negatives[avatar_names.index(dropdown)] - parse_yaml_dict(rawDict, "", avatar_prompts[avatar_names.index(dropdown)], dropdown, default_negative) - prompt_txt = "" - keys = list(filter(lambda x: x not in EXCLUDED_TAGS, OUTPUTS.keys())) - for style in keys: - for each_line in OUTPUTS[style]: - prompt_txt += each_line + '\n' - return [prompt_txt, gr.Row.update(visible=True)] - -def load_avartar(avatar_dict, customize_tags_positive): - avatars = yaml.load(avatar_dict, yaml.BaseLoader) - - for name, prompt in avatars.items(): - avatar_names.append(name) - if 'value' in prompt.keys(): - avatar_prompts.append(customize_tags_positive + ', ' + prompt['value']) - if 'negative' in prompt.keys(): - avatar_negatives.append(prompt['negative']) - return [gr.Dropdown.update(choices=avatar_names, value=avatar_names[0]), gr.Column.update(visible=True), gr.Group.update(visible=True)] - -def scan_outputs(avatar_name): - if avatar_name is None or len(avatar_name) == 0: - print("Please select avatar name first.") - return - root = OUTPATH_SAMPLES - global qc_dict - qc_dict = {} - for folder in os.listdir(root): - if os.path.isdir(root + folder) == False: - continue - - files = os.listdir(root + folder) - if 'Not-available.png' in files: - print('Skip '+ folder + ' not available.') - continue - if avatar_name + '.png' in files: - continue - for each_avatar in avatar_names: - if each_avatar + '.png' in files: - files.remove(each_avatar + '.png') - if len(files) == 0: - continue - qc_dict[folder] = [root + folder + '/' + file for file in files] - - if len(qc_dict.keys()) == 0: - return gr.Dropdown.update(choices=[]) - return gr.Dropdown.update(choices=list(qc_dict.keys()), value=list(qc_dict.keys())[0]) - -def update_gallery(dropdown, avatar): - root = OUTPATH_SAMPLES - global trg_img, current_folder - current_folder = root + dropdown - trg_img = root + dropdown + '/' + avatar + '.png' - return qc_dict[dropdown] - -def clean_select_picture(filename): - if current_folder == '': - print("Please select qc tag.") - return - for file in os.listdir(current_folder): - is_avatar = False - for each_avatar in avatar_names: - if each_avatar + '.png' == file: - is_avatar = True - break - if os.path.splitext(file)[0] in filename: - os.rename(current_folder+'/'+file, trg_img) - elif is_avatar == False: - os.remove(current_folder+'/'+file) - -def image_url(filedata): - if type(filedata) == dict and filedata["is_file"]: - filename = filedata["name"] - tempdir = os.path.normpath(tempfile.gettempdir()) - normfn = os.path.normpath(filename) - assert normfn.startswith(tempdir), 'trying to open image file not in temporary directory' - - image = Image.open(filename) - clean_select_picture(os.path.basename(filename)) - return Image.open(filename) - - if type(filedata) == list: - if len(filedata) == 0: - return None - - filedata = filedata[0] - - if filedata.startswith("data:image/png;base64,"): - filedata = filedata[len("data:image/png;base64,"):] - - filedata = base64.decodebytes(filedata.encode('utf-8')) - image = Image.open(io.BytesIO(filedata)) - return image - - - - - -class Script(scripts.Script): - def title(self): - return "Prompt gallery" - - def ui(self, is_img2img): - with gr.Group(): - with gr.Column(): - label_avatar = gr.Label("Upload avatars config") - avatar_dict = gr.File(label="Upload avatar prompt inputs", type='bytes') - - # copy_from_app_button = gr.Button("Copy From Prompt Preview") - - with gr.Group(): - with gr.Column(visible=False) as avatar_col: - label_presets = gr.Label("Presets") - dropdown = gr.Dropdown(label="Choose avatar", choices=[""], value="", type="value", elem_id="dropdown") - dropdown.save_to_config = True - with gr.Row(): - checkbox_iterate = gr.Checkbox(label="Iterate seed every line", value=False) - skip_exist = gr.Checkbox(value=True, label="skip exist") - default_negative = gr.Textbox(label="default_negative", lines=1) - default_positive = gr.Textbox(label="default_positive", lines=1) - prompt_dict = gr.File(label="Upload prompt dictionary", type='bytes') - with gr.Row(visible = False) as save_prompts: - open_button = gr.Button("Open outputs directory") - export_button = gr.Button("Export to WebUI style") - prompt_display = gr.Textbox(label="List of prompt inputs", lines=1) - - - prompt_dict.change(fn=load_prompt, inputs=[prompt_dict, default_negative, dropdown, skip_exist], outputs=[prompt_display, save_prompts]) - open_button.click(fn=lambda: open_folder(OUTPATH_SAMPLES), inputs=[], outputs=[]) - export_button.click(fn=save_styles, inputs=[], outputs=[]) - - with gr.Group(visible=False) as qc_widgets: - label_preview = gr.Label("QC preview") - with gr.Row(): - qc_refresh = gr.Button("QC scan") - preview_dropdown = gr.Dropdown(label="Select prompts", choices=[""], value="", type="value", elem_id="dropdown") - preview_gallery = gr.Gallery(label='Output', show_label=False, elem_id=f"preview_gallery").style(grid=4) - qc_refresh.click(fn=scan_outputs, inputs=[dropdown], outputs=preview_dropdown) - with gr.Row(): - qc_show = gr.Button(f"Show pics") - qc_select = gr.Button(f"Select") - rename_button = gr.Button("Auto rename") - selected_img = gr.Image(label="Selected",show_label=False, source="upload", interactive=True, type="pil").style(height=480) - qc_show.click(fn=update_gallery, inputs=[preview_dropdown, dropdown], outputs=preview_gallery) - qc_select.click( - fn=lambda x: image_url(x), - _js="extract_image_from_gallery", - inputs=[preview_gallery], - outputs=[selected_img], - ) - # qc_select.click(fn=select_picture, inputs=[dropdown, preview_dropdown, preview_gallery], outputs=[]) - rename_button.click(fn=rename_preview, inputs=[dropdown], outputs=[]) - # qc_select.click(fn=scan_outputs, inputs=[], outputs=[preview_dropdown]) - - avatar_dict.change(fn=load_avartar, inputs=[avatar_dict, default_positive], outputs=[dropdown, avatar_col, qc_widgets]) - return [checkbox_iterate, avatar_dict, prompt_dict, default_negative, default_positive, dropdown, prompt_display, rename_button, label_avatar, open_button, export_button, skip_exist, label_presets, label_preview, preview_dropdown, preview_gallery, qc_select, qc_refresh, qc_show, selected_img] - - def run(self, p, checkbox_iterate, avatar_dict, prompt_dict, default_negative, default_positive, dropdown, prompt_display, rename_button, label_avatar, open_button, export_button, skip_exist, label_presets, label_preview, preview_dropdown, preview_gallery, qc_select, qc_refresh, qc_show, selected_img): - lines = [x.strip() for x in prompt_display.splitlines()] - lines = [x for x in lines if len(x) > 0] - - p.do_not_save_grid = True - - job_count = 0 - jobs = [] - - for line in lines: - if "--" in line: - try: - args = cmdargs(line) - except Exception: - print(f"Error parsing line [line] as commandline:", file=sys.stderr) - print(traceback.format_exc(), file=sys.stderr) - args = {"prompt": line} - else: - args = {"prompt": line} - - n_iter = args.get("n_iter", 1) - if n_iter != 1: - job_count += n_iter - else: - job_count += 1 - - jobs.append(args) - - print(f"Will process {len(lines)} lines in {job_count} jobs.") - if (checkbox_iterate and p.seed == -1): - p.seed = int(random.randrange(4294967294)) - - state.job_count = job_count - - images = [] - for n, args in enumerate(jobs): - state.job = f"{state.job_no + 1} out of {state.job_count}" - - copy_p = copy.copy(p) - for k, v in args.items(): - setattr(copy_p, k, v) - - proc = process_images(copy_p) - images += proc.images - - if (checkbox_iterate): - p.seed = p.seed + (p.batch_size * p.n_iter) - - OUTPUTS = {} - rawDict = {} - - return Processed(p, images, p.seed, "") \ No newline at end of file +import modules.extras +import modules.ui +from modules.shared import opts, cmd_opts +from modules import shared, scripts +from modules import script_callbacks +from pathlib import Path +from typing import List, Tuple +import uvicorn +from uvicorn import Config +from fastapi import FastAPI +from fastapi.staticfiles import StaticFiles +import contextlib +import threading +import requests +from fastapi.middleware.cors import CORSMiddleware +import json + +def on_ui_settings(): + with open("./extensions/prompt_gallery_name.json") as fd: + name = json.load(fd)['name'] + app = FastAPI() + app.mount('/', StaticFiles(directory='./extensions/'+name,html=True)) + config = Config(app=app, host='localhost',port=5173, log_level="info", loop="asyncio", limit_max_requests=1) + app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"] + ) + + thread = threading.Thread(target= uvicorn.run, kwargs={'app':app, 'host': 'localhost', 'port':5173}) + thread.start() + tmp = requests.get("http://localhost:5173") + while tmp.status_code != 204 and tmp.status_code != 200: + time.sleep(0.01) + tmp = requests.get("http://localhost:5173") + pass + # thread.join() + + + +def on_ui_tabs(): + html = """""" + with gr.Blocks(analytics_enabled=False, elem_id="prompt_gallery") as prompt_gallery: + prompt_gallery = gr.HTML(html) + + return (prompt_gallery , "Prompt Gallery", "prompt_gallery"), + +script_callbacks.on_ui_tabs(on_ui_tabs) + +script_callbacks.on_ui_settings(on_ui_settings) \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100644 index a523b19..0000000 --- a/setup.py +++ /dev/null @@ -1,9 +0,0 @@ -import os -import shutil -import sys - -current_dir= os.path.abspath(os.path.dirname(__file__)) -print(os.path.join(os.path.join(current_dir,"extensions"),"prompt-gallery"), os.path.join(sys.argv[1],"extensions")) -print(os.path.join(current_dir,"scripts"), os.path.join(sys.argv[1],"scripts")) -shutil.copytree(os.path.join(os.path.join(current_dir,"extensions"),"prompt-gallery"), os.path.join(os.path.join(sys.argv[1],"extensions"),"prompt-gallery")) -shutil.copy(os.path.join(os.path.join(current_dir,"scripts"),"prompt_gallery.py"), os.path.join(sys.argv[1],"scripts")) \ No newline at end of file