Adding in the functionality for the extension

pull/1/head
Luke 2023-07-17 10:30:47 -06:00
parent 3f8299d89f
commit 8095929f1f
5 changed files with 246 additions and 0 deletions

16
README.md Normal file
View File

@ -0,0 +1,16 @@
# A simple history slider.
Similarly to that have DrawThings.ai but for AUTOMATIC 1111 Stable Diffusion Webui.
### Example
![Example](./img/253677295-95222051-85e9-4448-80cf-dc06fb42f309.gif "Example")
## What can it do?
- It will track both prompt and negative prompt history for txt2img and img2img.
- It will allow a user to load the history stored on local storage.
- It will allow a user to clear the prompt history.
## TODO
- Change the formatting of the local history to a singular instance using JSON to track steps.
- Put a max threshold on the prompt's history.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 MiB

168
javascript/history.js Normal file
View File

@ -0,0 +1,168 @@
const LOADED_STORAGE_KEY = "_history_is_loaded";
const TEXT_TO_IMAGE = "txt2img"
const IMAGE_TO_IMAGE = "img2img"
const HISTORY_TOP_ROW_POSTFIX = "_history_top_row"
function init() {
// Dynamically obtained from the objects being loaded into Gradio
txt2img_prompt.addEventListener("input", () => watchPrompts(TEXT_TO_IMAGE));
txt2img_neg_prompt.addEventListener("input", () => watchPrompts(TEXT_TO_IMAGE));
img2img_neg_prompt.addEventListener("input", () => watchPrompts(IMAGE_TO_IMAGE));
img2img_prompt.addEventListener("input", () => watchPrompts(IMAGE_TO_IMAGE));
}
function swapThem() {
// Swap from the lower end of the GUI to where we want them to, below the prompts
const tab = (get_uiCurrentTab()).innerHTML.trim();
if (tab == TEXT_TO_IMAGE || tab == IMAGE_TO_IMAGE) {
const top_row = document.getElementById(tab + "_toprow");
const history_top_row = document.getElementById(tab + HISTORY_TOP_ROW_POSTFIX);
top_row.after(history_top_row);
}
}
function changingTabs() {
// Listen for changing tabs.
const tab = (get_uiCurrentTab()).innerHTML.trim();
if (tab == TEXT_TO_IMAGE || tab == IMAGE_TO_IMAGE) {
// if (isLoaded(tab)) {
// load_history(tab);
// }
swapThem();
}
}
function isLoaded(tab) {
// This might be good for when we create a auto load checkbox.
console.log("is loaded?");
const t = window.localStorage.getItem(tab + LOADED_STORAGE_KEY) || false;
console.log(t);
return t;
}
function buildKey(a, b) {
return a + "_" + b;
}
function capturePrompts(tabname) {
const value = {};
value.negative_prompt = gradioApp().querySelector(
"#" + tabname + "_neg_prompt textarea"
).value;
value.prompt = gradioApp().querySelector(
"#" + tabname + "_prompt textarea"
).value;
return value;
}
function updatePromptHistory(tabname) {
const slider = gradioApp().querySelector(
"#" + tabname + "_prompt_history_slider> input"
);
const prompt = gradioApp().querySelector("#" + tabname + "_prompt textarea");
const negprompt = gradioApp().querySelector(
"#" + tabname + "_neg_prompt textarea"
);
const key = buildKey(tabname, slider.value);
const value = JSON.parse(window.localStorage.getItem(key));
prompt.value = value.prompt;
negprompt.value = value.negative_prompt;
}
function watchPrompts(tabname) {
const input = gradioApp().querySelector(
"#" + tabname + "_prompt_history_slider> div input"
);
const slider = gradioApp().querySelector(
"#" + tabname + "_prompt_history_slider> input"
);
slider.max = parseInt(slider.max) + 1;
slider.value = parseInt(slider.max);
input.value = parseInt(slider.value);
let value = capturePrompts(tabname);
let key = buildKey(tabname, slider.value);
window.localStorage.setItem(key, JSON.stringify(value));
}
function load_history(tabname) {
if (!isLoaded(tabname)) {
window.localStorage.setItem(buildKey(tabname, LOADED_STORAGE_KEY), true)
}
const slider = gradioApp().querySelector(
"#" + tabname + "_prompt_history_slider> input"
);
const input = gradioApp().querySelector(
"#" + tabname + "_prompt_history_slider> div input"
);
const items = {...window.localStorage};
let count = 0;
let last_prompt = "";
let last_neg_prompt = "";
for (let key in items) {
const re = new RegExp(tabname + "_[0-9]+", "g");
if (key.match(re)) {
count++;
}
}
if (count > 0) {
const value = JSON.parse(items[tabname + "_" + count]);
last_prompt = value.prompt;
last_neg_prompt = value.negative_prompt;
slider.max = parseInt(count);
slider.value = parseInt(count);
input.value = parseInt(count);
document.cookie = "isInit=true";
const prompt = gradioApp().querySelector(
"#" + tabname + "_prompt textarea"
);
const negprompt = gradioApp().querySelector(
"#" + tabname + "_neg_prompt textarea"
);
prompt.value = last_prompt;
negprompt.value = last_neg_prompt;
}
}
function confirm_clear_history(tabname) {
const slider = gradioApp().querySelector(
"#" + tabname + "_prompt_history_slider> input"
);
const input = gradioApp().querySelector(
"#" + tabname + "_prompt_history_slider> div input"
);
if (confirm("Clear " + tabname + " prompt history?")) {
slider.max = 1;
slider.value = 1;
input.value = 1;
const items = {...window.localStorage};
for (let key in items) {
const re = new RegExp(tabname + "_[0-9]+", "g");
if (key.match(re)) {
window.localStorage.removeItem(key);
}
}
window.localStorage.setItem(
buildKey(tabname, slider.value),
JSON.stringify(capturePrompts(tabname))
);
}
}
onUiLoaded(async () => {
swapThem();
init();
});
onUiTabChange(async () => { changingTabs() });

Binary file not shown.

62
scripts/history.py Normal file
View File

@ -0,0 +1,62 @@
import gradio as gr
from modules import scripts
from modules.ui_components import FormGroup
def create_history_slider(tabname):
with FormGroup(elem_id=f"prompt_history_slider_{tabname}"):
history = gr.Slider(
minimum=1,
maximum=1,
step=1,
elem_id=f"{tabname}_prompt_history_slider",
label="Prompt History",
value=1,
)
history.input(
fn=lambda *x: x,
_js="function(){updatePromptHistory('" + tabname + "')}",
inputs=None,
outputs=None,
)
history.release( #this is for the case where the user goes too fast or off the page.
fn=lambda *x: x,
_js="function(){updatePromptHistory('" + tabname + "')}",
inputs=None,
outputs=None,
)
return history
class HistoryScript(scripts.Script):
def __init__(self) -> None:
super().__init__()
def title(self):
return "History"
def show(self, is_img2img):
return scripts.AlwaysVisible
def ui(self, is_img2img):
id_part = "img2img" if is_img2img else "txt2img"
with gr.Row(elem_id=f"{id_part}_history_top_row", variant="compact", scale=100):
with gr.Column(elem_id="history_col", scale=11):
history_slider = create_history_slider(id_part)
with gr.Column(elem_id="history_col", scale=1):
with gr.Row(elem_id="history_button_row", variant="compact"):
clear_history = gr.Button("Clear", visible=True, label="Clear history")
clear_history.click(
fn=lambda *x: x,
_js="function(){confirm_clear_history('" + id_part + "')}",
inputs=None,
outputs=None,
)
load_history = gr.Button("Load", visible=True, label="Load history")
load_history.click(
fn=lambda *x: x,
_js="function(){load_history('" + id_part + "')}",
inputs=None,
outputs=None,
)
return [history_slider, clear_history, load_history]