add prompt history as suggested in #87
Signed-off-by: Victor Seiji Hariki <victorseijih@gmail.com>
This commit is contained in:
parent
34b995998b
commit
0a73687556
14 changed files with 526 additions and 81 deletions
231
css/index.css
231
css/index.css
|
@ -331,13 +331,48 @@ input#host {
|
|||
|
||||
/* Prompt Fields */
|
||||
|
||||
.content.prompt {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.content.prompt > .inputs {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
div.prompt-wrapper {
|
||||
display: flex;
|
||||
|
||||
width: calc(100%);
|
||||
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
div.prompt-wrapper > textarea {
|
||||
div.prompt-wrapper > * {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
div.prompt-wrapper textarea {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
border-radius: 0;
|
||||
|
||||
border: none;
|
||||
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
div.prompt-wrapper:not(:first-child) textarea {
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
|
||||
div.prompt-wrapper > textarea {
|
||||
box-sizing: border-box;
|
||||
width: calc(100% - 20px);
|
||||
|
||||
padding: 2px;
|
||||
|
||||
transition-duration: 200ms;
|
||||
|
||||
resize: vertical;
|
||||
}
|
||||
|
@ -346,6 +381,198 @@ div.prompt-wrapper > textarea:focus {
|
|||
width: 700px;
|
||||
}
|
||||
|
||||
div.prompt-wrapper > .prompt-indicator {
|
||||
display: flex;
|
||||
|
||||
cursor: help;
|
||||
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
div.prompt-wrapper:first-child > .prompt-indicator {
|
||||
border-top-left-radius: 5px;
|
||||
}
|
||||
|
||||
div.prompt-wrapper:last-child > .prompt-indicator {
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
|
||||
div.prompt-wrapper > .prompt-indicator.positive {
|
||||
background-color: #484;
|
||||
}
|
||||
|
||||
div.prompt-wrapper > .prompt-indicator.negative {
|
||||
background-color: #844;
|
||||
}
|
||||
div.prompt-wrapper > .prompt-indicator.styles {
|
||||
background-color: #448;
|
||||
}
|
||||
|
||||
div.prompt-wrapper > .prompt-indicator::after {
|
||||
content: "";
|
||||
display: block;
|
||||
margin: auto;
|
||||
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
background-color: var(--c-text);
|
||||
|
||||
mask-size: contain;
|
||||
-webkit-mask-size: contain;
|
||||
}
|
||||
|
||||
div.prompt-wrapper > .prompt-indicator.positive::after {
|
||||
mask-image: url("/res/icons/plus-square.svg");
|
||||
-webkit-mask-image: url("/res/icons/plus-square.svg");
|
||||
}
|
||||
|
||||
div.prompt-wrapper > .prompt-indicator.negative::after {
|
||||
mask-image: url("/res/icons/minus-square.svg");
|
||||
-webkit-mask-image: url("/res/icons/minus-square.svg");
|
||||
}
|
||||
|
||||
div.prompt-wrapper > .prompt-indicator.styles::after {
|
||||
mask-image: url("/res/icons/library.svg");
|
||||
-webkit-mask-image: url("/res/icons/library.svg");
|
||||
}
|
||||
|
||||
.prompt-history-wrapper {
|
||||
position: relative;
|
||||
|
||||
flex-shrink: 0;
|
||||
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.prompt-history-container {
|
||||
display: flex;
|
||||
|
||||
position: absolute;
|
||||
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#prompt-history {
|
||||
width: 0px;
|
||||
height: 100%;
|
||||
|
||||
transition-duration: 200ms;
|
||||
|
||||
background-color: #1e1e50;
|
||||
}
|
||||
|
||||
#prompt-history.expanded {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
#prompt-history .entry {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
justify-content: stretch;
|
||||
|
||||
border: 1px #fff3;
|
||||
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
#prompt-history.expanded .entry > button {
|
||||
padding: 2px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
#prompt-history .entry > button {
|
||||
flex: 1;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
|
||||
color: var(--c-text);
|
||||
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
transition-duration: 100ms;
|
||||
}
|
||||
|
||||
#prompt-history .entry:hover > button:not(:hover) {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
flex-basis: 20%;
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
#prompt-history .entry > button.prompt {
|
||||
background-color: #484;
|
||||
}
|
||||
|
||||
#prompt-history .entry > button.negative {
|
||||
background-color: #844;
|
||||
}
|
||||
|
||||
#prompt-history .entry > button.styles {
|
||||
background-color: #448;
|
||||
}
|
||||
|
||||
#prompt-history .entry > button:hover {
|
||||
filter: brightness(115%);
|
||||
backdrop-filter: brightness(115%);
|
||||
}
|
||||
|
||||
#prompt-history .entry > button:active {
|
||||
filter: brightness(150%);
|
||||
backdrop-filter: brightness(150%);
|
||||
}
|
||||
|
||||
button.prompt-history-btn {
|
||||
cursor: pointer;
|
||||
|
||||
border-radius: 0;
|
||||
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
|
||||
background-color: #1e1e50;
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
button.prompt-history-btn::after {
|
||||
content: "";
|
||||
display: block;
|
||||
margin: auto;
|
||||
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
background-color: var(--c-text);
|
||||
|
||||
mask-size: contain;
|
||||
-webkit-mask-size: contain;
|
||||
|
||||
mask-image: url("/res/icons/history.svg");
|
||||
-webkit-mask-image: url("/res/icons/history.svg");
|
||||
}
|
||||
|
||||
button.prompt-history-btn:hover {
|
||||
filter: brightness(115%);
|
||||
}
|
||||
|
||||
button.prompt-history-btn:active {
|
||||
filter: brightness(150%);
|
||||
}
|
||||
|
||||
/* Style Field */
|
||||
select > .style-select-option {
|
||||
position: relative;
|
||||
|
|
33
index.html
33
index.html
|
@ -51,19 +51,31 @@
|
|||
</label>
|
||||
<!-- Prompts section -->
|
||||
<button type="button" class="collapsible">Prompts</button>
|
||||
<div class="content">
|
||||
<label for="prompt">Prompt:</label>
|
||||
<br />
|
||||
<div class="content prompt">
|
||||
<div class="inputs">
|
||||
<div class="prompt-wrapper">
|
||||
<textarea id="prompt"></textarea>
|
||||
<div class="prompt-indicator positive" title="Prompt"></div>
|
||||
<textarea id="prompt" class="expandable"></textarea>
|
||||
</div>
|
||||
<label for="negPrompt">Negative prompt:</label>
|
||||
<div class="prompt-wrapper">
|
||||
<textarea id="negPrompt"></textarea>
|
||||
<div
|
||||
class="prompt-indicator negative"
|
||||
title="Negative Prompt"></div>
|
||||
<textarea id="negPrompt" class="expandable"></textarea>
|
||||
</div>
|
||||
<div class="prompt-wrapper">
|
||||
<div class="prompt-indicator styles" title="Styles"></div>
|
||||
<div id="style-ac-mselect" style="flex-shrink: 1"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="prompt-history-wrapper">
|
||||
<div class="prompt-history-container">
|
||||
<div id="prompt-history" class="expanded"></div>
|
||||
<button
|
||||
id="prompt-history-btn"
|
||||
class="prompt-history-btn"></button>
|
||||
</div>
|
||||
</div>
|
||||
<label for="styleSelect">Styles:</label>
|
||||
<div id="style-ac-mselect"></div>
|
||||
<!-- <hr /> -->
|
||||
</div>
|
||||
<!-- SD section -->
|
||||
<button type="button" class="collapsible">
|
||||
|
@ -286,6 +298,7 @@
|
|||
|
||||
<!-- Base Libs -->
|
||||
<script src="js/lib/util.js" type="text/javascript"></script>
|
||||
<script src="js/lib/events.js" type="text/javascript"></script>
|
||||
<script src="js/lib/input.js" type="text/javascript"></script>
|
||||
<script src="js/lib/layers.js" type="text/javascript"></script>
|
||||
<script src="js/lib/commands.js" type="text/javascript"></script>
|
||||
|
@ -298,7 +311,9 @@
|
|||
type="text/javascript"></script>
|
||||
|
||||
<!-- Content -->
|
||||
<script src="js/prompt.js" type="text/javascript"></script>
|
||||
<script src="js/index.js" type="text/javascript"></script>
|
||||
|
||||
<script src="js/ui/floating/history.js" type="text/javascript"></script>
|
||||
<script src="js/ui/floating/layers.js" type="text/javascript"></script>
|
||||
|
||||
|
|
67
js/index.js
67
js/index.js
|
@ -96,20 +96,6 @@ function startup() {
|
|||
};
|
||||
});
|
||||
|
||||
const promptEl = document.getElementById("prompt");
|
||||
promptEl.oninput = () => {
|
||||
stableDiffusionData.prompt = promptEl.value;
|
||||
promptEl.title = promptEl.value;
|
||||
localStorage.setItem("prompt", stableDiffusionData.prompt);
|
||||
};
|
||||
|
||||
const negPromptEl = document.getElementById("negPrompt");
|
||||
negPromptEl.oninput = () => {
|
||||
stableDiffusionData.negative_prompt = negPromptEl.value;
|
||||
negPromptEl.title = negPromptEl.value;
|
||||
localStorage.setItem("neg_prompt", stableDiffusionData.negative_prompt);
|
||||
};
|
||||
|
||||
drawBackground();
|
||||
changeMaskBlur();
|
||||
changeSmoothRendering();
|
||||
|
@ -447,12 +433,6 @@ const makeSlider = (
|
|||
});
|
||||
};
|
||||
|
||||
const styleAutoComplete = createAutoComplete(
|
||||
"Style",
|
||||
document.getElementById("style-ac-mselect"),
|
||||
{multiple: true}
|
||||
);
|
||||
|
||||
const modelAutoComplete = createAutoComplete(
|
||||
"Model",
|
||||
document.getElementById("models-ac-select")
|
||||
|
@ -784,49 +764,6 @@ async function getConfig() {
|
|||
}
|
||||
}
|
||||
|
||||
async function getStyles() {
|
||||
/** @type {HTMLSelectElement} */
|
||||
var styleSelect = document.getElementById("styleSelect");
|
||||
var url = document.getElementById("host").value + "/sdapi/v1/prompt-styles";
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
/** @type {{name: string, prompt: string, negative_prompt: string}[]} */
|
||||
const data = await response.json();
|
||||
|
||||
/** @type {string[]} */
|
||||
let stored = null;
|
||||
try {
|
||||
stored = JSON.parse(localStorage.getItem("promptStyle"));
|
||||
// doesn't seem to throw a syntaxerror if the localstorage item simply doesn't exist?
|
||||
if (stored == null) stored = [];
|
||||
} catch (e) {
|
||||
stored = [];
|
||||
}
|
||||
|
||||
styleAutoComplete.options = data.map((style) => ({
|
||||
name: style.name,
|
||||
value: style.name,
|
||||
title: `prompt: ${style.prompt}\nnegative: ${style.negative_prompt}`,
|
||||
}));
|
||||
styleAutoComplete.onchange.on(({value}) => {
|
||||
let selected = [];
|
||||
if (value.find((v) => v === "None")) {
|
||||
styleAutoComplete.value = [];
|
||||
} else {
|
||||
selected = value;
|
||||
}
|
||||
stableDiffusionData.styles = selected;
|
||||
localStorage.setItem("promptStyle", JSON.stringify(selected));
|
||||
});
|
||||
|
||||
styleAutoComplete.value = stored;
|
||||
localStorage.setItem("promptStyle", JSON.stringify(stored));
|
||||
} catch (e) {
|
||||
console.warn("[index] Failed to fetch prompt styles");
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
function changeStyles() {
|
||||
/** @type {HTMLSelectElement} */
|
||||
const styleSelectEl = document.getElementById("styleSelect");
|
||||
|
@ -958,10 +895,6 @@ function loadSettings() {
|
|||
);
|
||||
|
||||
// set the values into the UI
|
||||
document.getElementById("prompt").value = String(_prompt);
|
||||
document.getElementById("prompt").title = String(_prompt);
|
||||
document.getElementById("negPrompt").value = String(_negprompt);
|
||||
document.getElementById("negPrompt").title = String(_negprompt);
|
||||
document.getElementById("maskBlur").value = Number(_mask_blur);
|
||||
document.getElementById("seed").value = Number(_seed);
|
||||
document.getElementById("cbxHRFix").checked = Boolean(_enable_hr);
|
||||
|
|
|
@ -48,7 +48,7 @@ for (var i = 0; i < coll.length; i++) {
|
|||
if (active) content.style.maxHeight = content.scrollHeight + "px";
|
||||
});
|
||||
|
||||
Array.from(content.children).forEach((child) => {
|
||||
Array.from(content.querySelectorAll("*")).forEach((child) => {
|
||||
observer.observe(child);
|
||||
});
|
||||
|
||||
|
@ -62,6 +62,20 @@ for (var i = 0; i < coll.length; i++) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt history setup
|
||||
*/
|
||||
const _promptHistoryEl = document.getElementById("prompt-history");
|
||||
const _promptHistoryBtn = document.getElementById("prompt-history-btn");
|
||||
|
||||
_promptHistoryEl.addEventListener("mouseleave", () => {
|
||||
_promptHistoryEl.classList.remove("expanded");
|
||||
});
|
||||
|
||||
_promptHistoryBtn.addEventListener("click", () =>
|
||||
_promptHistoryEl.classList.toggle("expanded")
|
||||
);
|
||||
|
||||
/**
|
||||
* Settings overlay setup
|
||||
*/
|
||||
|
|
5
js/lib/events.js
Normal file
5
js/lib/events.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
const events = makeReadOnly({
|
||||
tool: {
|
||||
dream: new Observer(),
|
||||
},
|
||||
});
|
|
@ -80,6 +80,33 @@ const guid = (size = 3) => {
|
|||
return id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a hash code from a string
|
||||
*
|
||||
* From https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript
|
||||
*
|
||||
* @param {String} str The string to hash
|
||||
* @return {Number} A 32bit integer
|
||||
*/
|
||||
const hashCode = (str, seed = 0) => {
|
||||
let h1 = 0xdeadbeef ^ seed,
|
||||
h2 = 0x41c6ce57 ^ seed;
|
||||
for (let i = 0, ch; i < str.length; i++) {
|
||||
ch = str.charCodeAt(i);
|
||||
h1 = Math.imul(h1 ^ ch, 2654435761);
|
||||
h2 = Math.imul(h2 ^ ch, 1597334677);
|
||||
}
|
||||
|
||||
h1 =
|
||||
Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^
|
||||
Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
||||
h2 =
|
||||
Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^
|
||||
Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
||||
|
||||
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Assigns defaults to an option object passed to the function.
|
||||
*
|
||||
|
|
189
js/prompt.js
Normal file
189
js/prompt.js
Normal file
|
@ -0,0 +1,189 @@
|
|||
/**
|
||||
* This file is for processing prompt/negative prompt and prompt style data
|
||||
*/
|
||||
|
||||
// Prompt Style Element
|
||||
const styleSelectElement = createAutoComplete(
|
||||
"Style",
|
||||
document.getElementById("style-ac-mselect"),
|
||||
{multiple: true}
|
||||
);
|
||||
|
||||
// Function to get styles from AUTOMATIC1111 webui
|
||||
async function getStyles() {
|
||||
var url = document.getElementById("host").value + "/sdapi/v1/prompt-styles";
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
/** @type {{name: string, prompt: string, negative_prompt: string}[]} */
|
||||
const data = await response.json();
|
||||
|
||||
/** @type {string[]} */
|
||||
let stored = null;
|
||||
try {
|
||||
stored = JSON.parse(localStorage.getItem("promptStyle"));
|
||||
// doesn't seem to throw a syntaxerror if the localstorage item simply doesn't exist?
|
||||
if (stored == null) stored = [];
|
||||
} catch (e) {
|
||||
stored = [];
|
||||
}
|
||||
|
||||
styleSelectElement.options = data.map((style) => ({
|
||||
name: style.name,
|
||||
value: style.name,
|
||||
title: `prompt: ${style.prompt}\nnegative: ${style.negative_prompt}`,
|
||||
}));
|
||||
styleSelectElement.onchange.on(({value}) => {
|
||||
let selected = [];
|
||||
if (value.find((v) => v === "None")) {
|
||||
styleSelectElement.value = [];
|
||||
} else {
|
||||
selected = value;
|
||||
}
|
||||
stableDiffusionData.styles = selected;
|
||||
localStorage.setItem("promptStyle", JSON.stringify(selected));
|
||||
});
|
||||
|
||||
styleSelectElement.value = stored;
|
||||
localStorage.setItem("promptStyle", JSON.stringify(stored));
|
||||
} catch (e) {
|
||||
console.warn("[index] Failed to fetch prompt styles");
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
(async () => {
|
||||
// Default configurations
|
||||
const defaultPrompt =
|
||||
"ocean floor scientific expedition, underwater wildlife";
|
||||
const defaultNegativePrompt =
|
||||
"people, person, humans, human, divers, diver, glitch, error, text, watermark, bad quality, blurry";
|
||||
|
||||
// Prompt Elements
|
||||
const promptEl = document.getElementById("prompt");
|
||||
const negativePromptEl = document.getElementById("negPrompt");
|
||||
|
||||
// Add prompt change handlers
|
||||
promptEl.oninput = () => {
|
||||
stableDiffusionData.prompt = promptEl.value;
|
||||
promptEl.title = promptEl.value;
|
||||
localStorage.setItem("prompt", stableDiffusionData.prompt);
|
||||
};
|
||||
|
||||
negativePromptEl.oninput = () => {
|
||||
stableDiffusionData.negative_prompt = negativePromptEl.value;
|
||||
negativePromptEl.title = negativePromptEl.value;
|
||||
localStorage.setItem("neg_prompt", stableDiffusionData.negative_prompt);
|
||||
};
|
||||
|
||||
// Load from local storage if set
|
||||
const promptDefaultValue = localStorage.getItem("prompt") || defaultPrompt;
|
||||
const negativePromptDefaultValue =
|
||||
localStorage.getItem("neg_prompt") || defaultNegativePrompt;
|
||||
|
||||
promptEl.value = promptEl.title = promptDefaultValue;
|
||||
negativePromptEl.value = negativePromptEl.title = negativePromptDefaultValue;
|
||||
|
||||
/**
|
||||
* Prompt History
|
||||
*/
|
||||
|
||||
// Get history-related elements
|
||||
const promptHistoryEl = document.getElementById("prompt-history");
|
||||
|
||||
// History
|
||||
const history = [];
|
||||
|
||||
function syncPromptHistory() {
|
||||
const historyCopy = Array.from(history);
|
||||
historyCopy.reverse();
|
||||
|
||||
for (let i = 0; i < historyCopy.length; i++) {
|
||||
const historyItem = historyCopy[i];
|
||||
|
||||
const id = `prompt-history-${historyItem.id}`;
|
||||
if (promptHistoryEl.querySelector(`#${id}`)) break;
|
||||
|
||||
const historyEntry = document.createElement("div");
|
||||
historyEntry.classList.add("entry");
|
||||
historyEntry.id = id;
|
||||
historyEntry.title = `prompt: ${historyItem.prompt}\nnegative: ${
|
||||
historyItem.negative
|
||||
}\nstyles: ${historyItem.styles.join(", ")}`;
|
||||
|
||||
// Compare with previous
|
||||
const samePrompt =
|
||||
i !== historyCopy.length - 1 &&
|
||||
historyItem.prompt === historyCopy[i + 1].prompt;
|
||||
const sameNegativePrompt =
|
||||
i !== historyCopy.length - 1 &&
|
||||
historyItem.negative === historyCopy[i + 1].negative;
|
||||
const sameStyles =
|
||||
i !== historyCopy.length - 1 &&
|
||||
historyItem.styles.length === historyCopy[i + 1].styles.length &&
|
||||
!historyItem.styles.some(
|
||||
(v, index) => v !== historyCopy[i + 1].styles[index]
|
||||
);
|
||||
|
||||
const prompt = historyItem.prompt;
|
||||
const negative = historyItem.negative;
|
||||
const styles = historyItem.styles;
|
||||
|
||||
const promptBtn = document.createElement("button");
|
||||
promptBtn.classList.add("prompt");
|
||||
promptBtn.addEventListener("click", () => {
|
||||
stableDiffusionData.prompt = prompt;
|
||||
promptEl.title = prompt;
|
||||
promptEl.value = prompt;
|
||||
localStorage.setItem("prompt", prompt);
|
||||
});
|
||||
promptBtn.textContent = (samePrompt ? "= " : "") + prompt;
|
||||
|
||||
const negativeBtn = document.createElement("button");
|
||||
negativeBtn.classList.add("negative");
|
||||
negativeBtn.addEventListener("click", () => {
|
||||
stableDiffusionData.negative_prompt = negative;
|
||||
negativePromptEl.title = negative;
|
||||
negativePromptEl.value = negative;
|
||||
localStorage.setItem("neg_prompt", negative);
|
||||
});
|
||||
negativeBtn.textContent = (sameNegativePrompt ? "= " : "") + negative;
|
||||
|
||||
const stylesBtn = document.createElement("button");
|
||||
stylesBtn.classList.add("styles");
|
||||
stylesBtn.textContent = (sameStyles ? "= " : "") + styles.join(", ");
|
||||
stylesBtn.addEventListener("click", () => {
|
||||
styleSelectElement.value = styles;
|
||||
});
|
||||
|
||||
historyEntry.appendChild(promptBtn);
|
||||
historyEntry.appendChild(negativeBtn);
|
||||
historyEntry.appendChild(stylesBtn);
|
||||
|
||||
promptHistoryEl.insertBefore(historyEntry, promptHistoryEl.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
// Listen for dreaming to add to history
|
||||
events.tool.dream.on((message) => {
|
||||
const {event} = message;
|
||||
if (event === "generate") {
|
||||
const {prompt, negative_prompt, styles} = message.request;
|
||||
const hash = hashCode(
|
||||
`p: ${prompt}, n: ${negative_prompt}, s: ${JSON.stringify(styles)}`
|
||||
);
|
||||
if (
|
||||
!history[history.length - 1] ||
|
||||
history[history.length - 1].hash !== hash
|
||||
)
|
||||
history.push({
|
||||
id: guid(),
|
||||
hash,
|
||||
prompt,
|
||||
negative: negative_prompt,
|
||||
styles,
|
||||
});
|
||||
}
|
||||
|
||||
syncPromptHistory();
|
||||
});
|
||||
})();
|
|
@ -120,6 +120,8 @@ const _generate = async (
|
|||
bb,
|
||||
drawEvery = 0.2 / request.n_iter
|
||||
) => {
|
||||
events.tool.dream.emit({event: "generate", request});
|
||||
|
||||
const requestCopy = JSON.parse(JSON.stringify(request));
|
||||
|
||||
// Block requests to identical areas
|
||||
|
|
6
res/icons/history.svg
Normal file
6
res/icons/history.svg
Normal file
|
@ -0,0 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 3v5h5"></path>
|
||||
<path d="M3.05 13A9 9 0 1 0 6 5.3L3 8"></path>
|
||||
<path d="M12 7v5l4 2"></path>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 299 B |
7
res/icons/library.svg
Normal file
7
res/icons/library.svg
Normal file
|
@ -0,0 +1,7 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="m16 6 4 14"></path>
|
||||
<path d="M12 6v14"></path>
|
||||
<path d="M8 8v12"></path>
|
||||
<path d="M4 4v16"></path>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 305 B |
5
res/icons/minus-square.svg
Normal file
5
res/icons/minus-square.svg
Normal file
|
@ -0,0 +1,5 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
||||
<line x1="8" y1="12" x2="16" y2="12"></line>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 301 B |
4
res/icons/minus.svg
Normal file
4
res/icons/minus.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="5" y1="12" x2="19" y2="12"></line>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 236 B |
6
res/icons/plus-square.svg
Normal file
6
res/icons/plus-square.svg
Normal file
|
@ -0,0 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
||||
<line x1="12" y1="8" x2="12" y2="16"></line>
|
||||
<line x1="8" y1="12" x2="16" y2="12"></line>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 348 B |
5
res/icons/plus.svg
Normal file
5
res/icons/plus.svg
Normal file
|
@ -0,0 +1,5 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="12" y1="5" x2="12" y2="19"></line>
|
||||
<line x1="5" y1="12" x2="19" y2="12"></line>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 283 B |
Loading…
Reference in a new issue