From 1c44b0b41cc3287cd6361eddabd9c1fbc2f5c717 Mon Sep 17 00:00:00 2001 From: GeorgLegato Date: Wed, 26 Apr 2023 05:49:16 +0200 Subject: [PATCH] added Prefix,Suffix, Toolltips, Accordions for sectionizing groups --- iz_helpers/helpers.py | 7 +- iz_helpers/prompt_util.py | 8 +- iz_helpers/promptschema.json | 8 +- iz_helpers/run.py | 13 +- iz_helpers/static_variables.py | 10 +- iz_helpers/ui.py | 204 ++++++++++++++++-------------- javascript/infinite-zoom-hints.js | 50 ++++++++ javascript/infinite-zoom.js | 4 +- 8 files changed, 191 insertions(+), 113 deletions(-) create mode 100644 javascript/infinite-zoom-hints.js diff --git a/iz_helpers/helpers.py b/iz_helpers/helpers.py index 2383712..4373bac 100644 --- a/iz_helpers/helpers.py +++ b/iz_helpers/helpers.py @@ -100,8 +100,10 @@ def putPrompts(files): data = readJsonPrompt(file_contents,False) return [ + gr.Textbox.update(data["commonPromptPrefix"]), gr.DataFrame.update(data["prompts"]), - gr.Textbox.update(data["negPrompt"]), + gr.Textbox.update(data["commonPromptSuffix"]), + gr.Textbox.update(data["negPrompt"]) ] except Exception: @@ -112,12 +114,13 @@ def putPrompts(files): # error only be shown with raise, so ui gets broken. #asyncio.run(showGradioErrorAsync("Loading your prompts failed. It seems to be invalid. Your prompt table has been preserved.",5)) - return [gr.DataFrame.update(), gr.Textbox.update()] + return [gr.Textbox.update(), gr.DataFrame.update(), gr.Textbox.update(),gr.Textbox.update()] def clearPrompts(): return [ gr.DataFrame.update(value=[[0, "Infinite Zoom. Start over"]]), gr.Textbox.update(""), + gr.Textbox.update(""), gr.Textbox.update("") ] diff --git a/iz_helpers/prompt_util.py b/iz_helpers/prompt_util.py index e689528..a1bd445 100644 --- a/iz_helpers/prompt_util.py +++ b/iz_helpers/prompt_util.py @@ -68,4 +68,10 @@ def readJsonPrompt(txt, returnFailPrompt=False): return invalid_prompt raise (f"Infinite Zoom: Corrupted Json structure: {txt[:24]} ...") - return validatePromptJson_throws(jpr) + try: + return validatePromptJson_throws(jpr) + except Exception: + if returnFailPrompt: + return invalid_prompt + pass + \ No newline at end of file diff --git a/iz_helpers/promptschema.json b/iz_helpers/promptschema.json index 1598454..396a554 100644 --- a/iz_helpers/promptschema.json +++ b/iz_helpers/promptschema.json @@ -47,13 +47,17 @@ "negPrompt": { "type": "string" }, - "commonPrompt": { + "commonPromptPrefix": { + "type": "string" + }, + "commonPromptSuffix": { "type": "string" } }, "required": [ "prompts", "negPrompt", - "commonPrompt" + "commonPromptPrefix", + "commonPromptSuffix" ] } \ No newline at end of file diff --git a/iz_helpers/run.py b/iz_helpers/run.py index 0a9789a..ed15bfd 100644 --- a/iz_helpers/run.py +++ b/iz_helpers/run.py @@ -16,8 +16,9 @@ from .video import write_video def create_zoom( - common_prompt, + common_prompt_pre, prompts_array, + common_prompt_suf, negative_prompt, num_outpainting_steps, guidance_scale, @@ -47,8 +48,9 @@ def create_zoom( for i in range(batchcount): print(f"Batch {i+1}/{batchcount}") result = create_zoom_single( - common_prompt, + common_prompt_pre, prompts_array, + common_prompt_suf, negative_prompt, num_outpainting_steps, guidance_scale, @@ -78,8 +80,9 @@ def create_zoom( def create_zoom_single( - common_prompt, + common_prompt_pre, prompts_array, + common_prompt_suf, negative_prompt, num_outpainting_steps, guidance_scale, @@ -144,7 +147,7 @@ def create_zoom_single( pr = prompts[min(k for k in prompts.keys() if k >= 0)] processed, newseed = renderTxt2Img( - f"{common_prompt}\n{pr}" if common_prompt else pr, + f"{common_prompt_pre}\n{pr}\n{common_prompt_suf}".strip(), negative_prompt, sampler, num_inference_steps, @@ -209,7 +212,7 @@ def create_zoom_single( else: pr = prompts[max(k for k in prompts.keys() if k <= i)] processed, newseed = renderImg2Img( - f"{common_prompt}\n{pr}" if common_prompt else pr, + f"{common_prompt_pre}\n{pr}\n{common_prompt_suf}".strip(), negative_prompt, sampler, num_inference_steps, diff --git a/iz_helpers/static_variables.py b/iz_helpers/static_variables.py index efa83dd..b52b31d 100644 --- a/iz_helpers/static_variables.py +++ b/iz_helpers/static_variables.py @@ -4,19 +4,20 @@ import modules.sd_samplers default_prompt = """ { + "commonPromptPrefix":" ", "prompts":{ "headers":["outpaint steps","prompt","img"], "data":[ [0,"Huge spectacular Waterfall in a dense tropical forest,epic perspective,(vegetation overgrowth:1.3)(intricate, ornamentation:1.1),(baroque:1.1), fantasy, (realistic:1) digital painting , (magical,mystical:1.2) , (wide angle shot:1.4), (landscape composed:1.2)(medieval:1.1), divine,cinematic,(tropical forest:1.4),(river:1.3)mythology,india, volumetric lighting, Hindu ,epic"] ] }, - "negPrompt":"frames, border, edges, borderline, text, character, duplicate, error, out of frame, watermark, low quality, ugly, deformed, blur bad-artist", - "commonPrompt":"style by Alex Horley Wenjun Lin greg rutkowski Ruan Jia (Wayne Barlowe:1.2), " + "commonPromptSuffix":"style by Alex Horley Wenjun Lin greg rutkowski Ruan Jia (Wayne Barlowe:1.2)", + "negPrompt":"frames, border, edges, borderline, text, character, duplicate, error, out of frame, watermark, low quality, ugly, deformed, blur, bad-artist" } """ empty_prompt = ( - '{"prompts":{"data":[],"headers":["outpaint steps","prompt"]},"negPrompt":"", commonPrompt:""}' + '{"prompts":{"data":[],"headers":["outpaint steps","prompt"]},"negPrompt":"", commonPromptPrefix:"", commonPromptSuffix}' ) invalid_prompt = { @@ -25,7 +26,8 @@ invalid_prompt = { "headers": ["outpaint steps", "prompt"], }, "negPrompt": "Invalid prompt-json", - "commonPrompt": "Invalid prompt" + "commonPromptPrefix": "Invalid prompt", + "commonPromptSuffix": "Invalid prompt" } available_samplers = [ diff --git a/iz_helpers/ui.py b/iz_helpers/ui.py index d1d52c3..afb0e12 100644 --- a/iz_helpers/ui.py +++ b/iz_helpers/ui.py @@ -28,6 +28,15 @@ def on_ui_tabs(): with gr.Row(): with gr.Column(scale=1, variant="panel"): with gr.Tab("Main"): + + batchcount_slider = gr.Slider( + minimum=1, + maximum=25, + value=shared.opts.data.get("infzoom_batchcount", 1), + step=1, + label="Batch Count", + ) + main_outpaint_steps = gr.Slider( minimum=2, maximum=100, @@ -41,111 +50,111 @@ def on_ui_tabs(): pr = shared.opts.data.get("infzoom_defPrompt", default_prompt) jpr = readJsonPrompt(pr, True) - main_common_prompt = gr.Textbox( - value=jpr["commonPrompt"], label="Common Prompt" - ) + with gr.Accordion(label="Prompt Section"): + main_common_prompt_pre = gr.Textbox( + value=jpr["commonPromptPrefix"], label="Common Prompt Prefix" + ) - main_prompts = gr.Dataframe( - type="array", - headers=["outpaint step", "prompt"], - datatype=["number", "str"], - row_count=1, - col_count=(2, "fixed"), - value=jpr["prompts"], - wrap=True, - ) + main_prompts = gr.Dataframe( + type="array", + headers=["outpaint step", "prompt"], + datatype=["number", "str"], + row_count=1, + col_count=(2, "fixed"), + value=jpr["prompts"], + wrap=True, + ) - main_negative_prompt = gr.Textbox( - value=jpr["negPrompt"], label="Negative Prompt" - ) + main_common_prompt_suf = gr.Textbox( + value=jpr["commonPromptSuffix"], label="Common Prompt Suffix" + ) - # these button will be moved using JS unde the dataframe view as small ones - exportPrompts_button = gr.Button( - value="Export prompts", - variant="secondary", - elem_classes="sm infzoom_tab_butt", - elem_id="infzoom_exP_butt", - ) - importPrompts_button = gr.UploadButton( - label="Import prompts", - variant="secondary", - elem_classes="sm infzoom_tab_butt", - elem_id="infzoom_imP_butt", - ) - exportPrompts_button.click( - None, - _js="exportPrompts", - inputs=[main_prompts, main_negative_prompt], - outputs=None - ) - importPrompts_button.upload( - fn=putPrompts, - outputs=[main_prompts, main_negative_prompt], - inputs=[importPrompts_button], - ) + main_negative_prompt = gr.Textbox( + value=jpr["negPrompt"], label="Negative Prompt" + ) - clearPrompts_button = gr.Button( - value="Clear prompts", - variant="secondary", - elem_classes="sm infzoom_tab_butt", - elem_id="infzoom_clP_butt", - ) - clearPrompts_button.click( - fn=clearPrompts, - inputs=[], - outputs=[main_prompts, main_negative_prompt, main_common_prompt], - ) - with gr.Row(): - seed = gr.Number( - label="Seed", value=-1, precision=0, interactive=True + # these button will be moved using JS unde the dataframe view as small ones + exportPrompts_button = gr.Button( + value="Export prompts", + variant="secondary", + elem_classes="sm infzoom_tab_butt", + elem_id="infzoom_exP_butt", ) - main_sampler = gr.Dropdown( - label="Sampler", - choices=available_samplers, - value="Euler a", - type="value", + importPrompts_button = gr.UploadButton( + label="Import prompts", + variant="secondary", + elem_classes="sm infzoom_tab_butt", + elem_id="infzoom_imP_butt", ) - with gr.Row(): - main_width = gr.Slider( - minimum=16, - maximum=2048, - value=shared.opts.data.get("infzoom_outsizeW", 512), - step=16, - label="Output Width", + exportPrompts_button.click( + None, + _js="exportPrompts", + inputs=[main_common_prompt_pre, main_prompts, main_common_prompt_suf, main_negative_prompt], + outputs=None ) - main_height = gr.Slider( - minimum=16, - maximum=2048, - value=shared.opts.data.get("infzoom_outsizeH", 512), - step=16, - label="Output Height", + importPrompts_button.upload( + fn=putPrompts, + outputs=[main_common_prompt_pre, main_prompts,main_common_prompt_suf , main_negative_prompt], + inputs=[importPrompts_button], ) - with gr.Row(): - main_guidance_scale = gr.Slider( - minimum=0.1, - maximum=15, - step=0.1, - value=7, - label="Guidance Scale", - ) - sampling_step = gr.Slider( - minimum=1, - maximum=100, - step=1, - value=50, - label="Sampling Steps for each outpaint", - ) - with gr.Row(): - init_image = gr.Image(type="pil", label="custom initial image") - exit_image = gr.Image(type="pil", label="custom exit image") - batchcount_slider = gr.Slider( - minimum=1, - maximum=25, - value=shared.opts.data.get("infzoom_batchcount", 1), - step=1, - label="Batch Count", - ) + clearPrompts_button = gr.Button( + value="Clear prompts", + variant="secondary", + elem_classes="sm infzoom_tab_butt", + elem_id="infzoom_clP_butt", + ) + clearPrompts_button.click( + fn=clearPrompts, + inputs=[], + outputs=[main_prompts, main_negative_prompt, main_common_prompt_pre, main_common_prompt_suf], + ) + + with gr.Accordion("Render settings"): + with gr.Row(): + seed = gr.Number( + label="Seed", value=-1, precision=0, interactive=True + ) + main_sampler = gr.Dropdown( + label="Sampler", + choices=available_samplers, + value="Euler a", + type="value", + ) + with gr.Row(): + main_width = gr.Slider( + minimum=16, + maximum=2048, + value=shared.opts.data.get("infzoom_outsizeW", 512), + step=16, + label="Output Width", + ) + main_height = gr.Slider( + minimum=16, + maximum=2048, + value=shared.opts.data.get("infzoom_outsizeH", 512), + step=16, + label="Output Height", + ) + with gr.Row(): + main_guidance_scale = gr.Slider( + minimum=0.1, + maximum=15, + step=0.1, + value=7, + label="Guidance Scale", + ) + sampling_step = gr.Slider( + minimum=1, + maximum=100, + step=1, + value=50, + label="Sampling Steps for each outpaint", + ) + with gr.Row(): + init_image = gr.Image(type="pil", label="Custom initial image") + exit_image = gr.Image(type="pil", label="Custom exit image") + with gr.Tab("Video"): video_frame_rate = gr.Slider( label="Frames per second", @@ -233,8 +242,9 @@ Our best experience and trade-off is the R-ERSGAn4x upscaler. generate_btn.click( fn=wrap_gradio_gpu_call(create_zoom, extra_outputs=[None, "", ""]), inputs=[ - main_common_prompt, + main_common_prompt_pre, main_prompts, + main_common_prompt_suf, main_negative_prompt, main_outpaint_steps, main_guidance_scale, diff --git a/javascript/infinite-zoom-hints.js b/javascript/infinite-zoom-hints.js new file mode 100644 index 0000000..d54d604 --- /dev/null +++ b/javascript/infinite-zoom-hints.js @@ -0,0 +1,50 @@ +// mouseover tooltips for various UI elements + +infzoom_titles = { + "Batch Count":"How many separate videos to create", + "Total Outpaint Steps":"Each step generates frame for 1 second at your FPS, while cycling through your array of prompts", + "Common Prompt Prefix":"Prompt inserted before each step", + "Common Prompt Suffix":"Prompt inserted after each step", + "Negative Prompt":"What your model shall avoid", + "Export prompts": "Downloads a JSON file to save all prompts", + "Import prompts": "Restore Prompts table from a specific JSON file", + "Clear prompts": "Start over, remove all entries from prompt table, prefix, suffix, negative", + "Custom initial image":"An image at the end resp. begin of your movie, depending or ZoomIn or Out", + "Custom exit image":"An image at the end resp. begin of your movie, depending or ZoomIn or Out", + "Zoom Speed":"Varies additional frames per second", + + + +} + + +onUiUpdate(function(){ + gradioApp().querySelectorAll('span, button, select, p').forEach(function(span){ + tooltip = infzoom_titles[span.textContent]; + + if(!tooltip){ + tooltip = infzoom_titles[span.value]; + } + + if(!tooltip){ + for (const c of span.classList) { + if (c in infzoom_titles) { + tooltip = infzoom_titles[c]; + break; + } + } + } + + if(tooltip){ + span.title = tooltip; + } + }) + + gradioApp().querySelectorAll('select').forEach(function(select){ + if (select.onchange != null) return; + + select.onchange = function(){ + select.title = infzoom_titles[select.value] || ""; + } + }) +}) diff --git a/javascript/infinite-zoom.js b/javascript/infinite-zoom.js index 0a41d0c..834d8fb 100644 --- a/javascript/infinite-zoom.js +++ b/javascript/infinite-zoom.js @@ -1,7 +1,7 @@ // Function to download data to a file -function exportPrompts(cp,p, np, filename = "infinite-zoom-prompts.json") { +function exportPrompts(cppre,p, cpsuf,np, filename = "infinite-zoom-prompts.json") { - let J = { prompts: p, negPrompt: np, commonPrompt: cp } + let J = { prompts: p, negPrompt: np, commonPromptPrefix: cppre, commonPromptSuffix: cpsuf } var file = new Blob([JSON.stringify(J)], { type: "text/csv" }); if (window.navigator.msSaveOrOpenBlob) // IE10+