mirror of
https://github.com/Sygil-Dev/sygil-webui.git
synced 2024-12-14 05:58:18 +03:00
floating suggestions area, first context sensitive responses (type by and get artist list), automated recognition of words "of, at, with" to not add a ",".
complex pattern matching support, to remove double "," and double text generation in general. improved key phrase list. full artist thumbnails support.
This commit is contained in:
parent
d5642806f1
commit
aa3f92b611
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1,329 +0,0 @@
|
||||
// parent document
|
||||
var parentDoc = window.parent.document;
|
||||
// iframe element in parent document
|
||||
var frame = window.frameElement;
|
||||
// the area to put the suggestions in
|
||||
var suggestionArea = document.getElementById('suggestion_area');
|
||||
// button height is read when the first button gets created
|
||||
var buttonHeight = -1;
|
||||
// the maximum size of the iframe in buttons (3 x buttons height)
|
||||
var maxHeightInButtons = 3;
|
||||
// the prompt field connected to this iframe
|
||||
var promptField = null;
|
||||
// the category of suggestions
|
||||
var activeCategory = [];
|
||||
|
||||
var conditionalButtons = null;
|
||||
|
||||
function currentFrameAbsolutePosition() {
|
||||
let currentWindow = window;
|
||||
let currentParentWindow;
|
||||
let positions = [];
|
||||
let rect;
|
||||
|
||||
while (currentWindow !== window.top) {
|
||||
currentParentWindow = currentWindow.parent;
|
||||
for (let idx = 0; idx < currentParentWindow.frames.length; idx++)
|
||||
if (currentParentWindow.frames[idx] === currentWindow) {
|
||||
for (let frameElement of currentParentWindow.document.getElementsByTagName('iframe')) {
|
||||
if (frameElement.contentWindow === currentWindow) {
|
||||
rect = frameElement.getBoundingClientRect();
|
||||
positions.push({x: rect.x, y: rect.y});
|
||||
}
|
||||
}
|
||||
currentWindow = currentParentWindow;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return positions.reduce((accumulator, currentValue) => {
|
||||
return {
|
||||
x: accumulator.x + currentValue.x,
|
||||
y: accumulator.y + currentValue.y
|
||||
};
|
||||
}, { x: 0, y: 0 });
|
||||
}
|
||||
|
||||
// check if element is visible
|
||||
function isVisible(e) {
|
||||
return !!( e.offsetWidth || e.offsetHeight || e.getClientRects().length );
|
||||
}
|
||||
|
||||
// remove everything from the suggestion area
|
||||
function ClearSuggestionArea(text = "")
|
||||
{
|
||||
suggestionArea.innerHTML = text;
|
||||
conditionalButtons = [];
|
||||
}
|
||||
|
||||
// update iframe size depending on button rows
|
||||
function UpdateSize()
|
||||
{
|
||||
// calculate maximum height
|
||||
var maxHeight = buttonHeight * maxHeightInButtons;
|
||||
// apply height to iframe
|
||||
frame.style.height = Math.min(suggestionArea.offsetHeight,maxHeight)+"px";
|
||||
}
|
||||
|
||||
// add a button to the suggestion area
|
||||
function AddButton(label, action, dataTooltip="", tooltipImage="", pattern="", data="")
|
||||
{
|
||||
// create span
|
||||
var button = document.createElement("span");
|
||||
// label it
|
||||
button.innerHTML = label;
|
||||
if(data != "")
|
||||
{
|
||||
// add category attribute to button, will be read on click
|
||||
button.setAttribute("data",data);
|
||||
}
|
||||
if(pattern != "")
|
||||
{
|
||||
// add category attribute to button, will be read on click
|
||||
button.setAttribute("pattern",pattern);
|
||||
}
|
||||
if(dataTooltip != "")
|
||||
{
|
||||
// add category attribute to button, will be read on click
|
||||
button.setAttribute("tooltip-text",dataTooltip);
|
||||
}
|
||||
if(tooltipImage != "")
|
||||
{
|
||||
// add category attribute to button, will be read on click
|
||||
button.setAttribute("tooltip-image",tooltipImage);
|
||||
}
|
||||
// add button function
|
||||
button.addEventListener('click', action, false);
|
||||
button.addEventListener('mouseover', ButtonHoverEnter);
|
||||
button.addEventListener('mouseout', ButtonHoverExit);
|
||||
// add button to suggestion area
|
||||
suggestionArea.appendChild(button);
|
||||
// get buttonHeight if not set
|
||||
if(buttonHeight < 0)
|
||||
buttonHeight = button.offsetHeight;
|
||||
return button;
|
||||
}
|
||||
|
||||
// find visible prompt field to connect to this iframe
|
||||
function GetPromptField()
|
||||
{
|
||||
// get all prompt fields, the %% placeholder %% is set in python
|
||||
var all = parentDoc.querySelectorAll('textarea[placeholder="'+placeholder+'"]');
|
||||
// filter visible
|
||||
for(var i = 0; i < all.length; i++)
|
||||
{
|
||||
if(isVisible(all[i]))
|
||||
{
|
||||
promptField = all[i];
|
||||
promptField.addEventListener('input', OnChange, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function OnChange(e)
|
||||
{
|
||||
ButtonConditions();
|
||||
}
|
||||
|
||||
// when pressing a button, give the focus back to the prompt field
|
||||
function KeepFocus(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
promptField.focus();
|
||||
}
|
||||
|
||||
function selectCategory(e)
|
||||
{
|
||||
KeepFocus(e);
|
||||
// set category from attribute
|
||||
activeCategory = e.target.getAttribute("data");
|
||||
// rebuild menu
|
||||
ShowMenu();
|
||||
}
|
||||
|
||||
function leaveCategory(e)
|
||||
{
|
||||
KeepFocus(e);
|
||||
activeCategory = "";
|
||||
// rebuild menu
|
||||
ShowMenu();
|
||||
}
|
||||
|
||||
function SelectPhrase(e)
|
||||
{
|
||||
KeepFocus(e);
|
||||
var pattern = e.target.getAttribute("pattern");
|
||||
var entry = e.target.getAttribute("data");
|
||||
|
||||
// inserting via execCommand is required, this triggers all native browser functionality as if the user wrote into the prompt field.
|
||||
parentDoc.execCommand('insertText', false /*no UI*/, pattern.replace('{}',entry));
|
||||
}
|
||||
|
||||
function CheckButtonCondition(condition)
|
||||
{
|
||||
if(condition === "empty")
|
||||
{
|
||||
return promptField.value == "";
|
||||
}
|
||||
}
|
||||
|
||||
function ButtonConditions()
|
||||
{
|
||||
conditionalButtons.forEach(entry =>
|
||||
{
|
||||
if(CheckButtonCondition(entry.condition))
|
||||
entry.element.style.display = "inline-block";
|
||||
else
|
||||
entry.element.style.display = "none";
|
||||
});
|
||||
}
|
||||
|
||||
function ButtonHoverEnter(e)
|
||||
{
|
||||
var text = e.target.getAttribute("tooltip-text");
|
||||
var image = e.target.getAttribute("tooltip-image");
|
||||
ShowTooltip(text, e.target, image)
|
||||
}
|
||||
|
||||
function ButtonHoverExit(e)
|
||||
{
|
||||
HideTooltip();
|
||||
}
|
||||
|
||||
function ShowTooltip(text, target, image = "")
|
||||
{
|
||||
if((text == "" || text == null) && (image == "" || image == null || thumbnails[image] === undefined))
|
||||
return;
|
||||
|
||||
var currentFramePosition = currentFrameAbsolutePosition();
|
||||
var rect = target.getBoundingClientRect();
|
||||
var element = parentDoc["phraseTooltip"];
|
||||
element.innerText = text;
|
||||
if(image != "" && image != null && thumbnails[image] !== undefined)
|
||||
{
|
||||
|
||||
var img = parentDoc.createElement('img');
|
||||
console.log(image);
|
||||
img.src = "data:image/webp;base64, "+thumbnails[image];
|
||||
|
||||
console.log(thumbnails[image]);
|
||||
element.appendChild(img)
|
||||
}
|
||||
element.style.display = "flex";
|
||||
element.style.top = (rect.bottom+currentFramePosition.y)+"px";
|
||||
element.style.left = (rect.right+currentFramePosition.x)+"px";
|
||||
element.style.width = "inherit";
|
||||
element.style.height = "inherit";
|
||||
}
|
||||
|
||||
function HideTooltip()
|
||||
{
|
||||
var element = parentDoc["phraseTooltip"];
|
||||
element.style.display= "none";
|
||||
element.innerHTML = "";
|
||||
element.style.top = "0px";
|
||||
element.style.left = "0px";
|
||||
element.style.width = "0px";
|
||||
element.style.height = "0px";
|
||||
}
|
||||
|
||||
// generate menu in suggestion area
|
||||
function ShowMenu()
|
||||
{
|
||||
// clear all buttons from menu
|
||||
ClearSuggestionArea();
|
||||
HideTooltip();
|
||||
|
||||
// if no chategory is selected
|
||||
if(activeCategory == "")
|
||||
{
|
||||
for (var category in keyPhrases)
|
||||
{
|
||||
AddButton(category, selectCategory, keyPhrases[category]["description"], "", "", category);
|
||||
}
|
||||
// change iframe size after buttons have been added
|
||||
UpdateSize();
|
||||
}
|
||||
// if a chategory is selected
|
||||
else
|
||||
{
|
||||
// add a button to leave the chategory
|
||||
var backbutton = AddButton("↑ back", leaveCategory);
|
||||
var pattern = keyPhrases[activeCategory]["pattern"];
|
||||
keyPhrases[activeCategory]["entries"].forEach(entry =>
|
||||
{
|
||||
var tempPattern = pattern;
|
||||
if(entry["pattern_override"] != "")
|
||||
{
|
||||
tempPattern = entry["pattern_override"];
|
||||
}
|
||||
|
||||
var button = AddButton(entry["phrase"], SelectPhrase, entry["description"], entry["phrase"],tempPattern, entry["phrase"]);
|
||||
|
||||
if(entry["show_if"] != "")
|
||||
conditionalButtons.push({element:button,condition:entry["show_if"]});
|
||||
});
|
||||
// change iframe size after buttons have been added
|
||||
UpdateSize();
|
||||
ButtonConditions();
|
||||
}
|
||||
}
|
||||
|
||||
// listen for clicks on the prompt field
|
||||
parentDoc.addEventListener("click", (e) =>
|
||||
{
|
||||
// skip if this frame is not visible
|
||||
if(!isVisible(frame))
|
||||
return;
|
||||
|
||||
// if the iframes prompt field is not set, get it and set it
|
||||
if(promptField === null)
|
||||
GetPromptField();
|
||||
|
||||
// get the field with focus
|
||||
var target = parentDoc.activeElement;
|
||||
|
||||
// if the field with focus is a prompt field, the %% placeholder %% is set in python
|
||||
if( target.placeholder === placeholder)
|
||||
{
|
||||
// generate menu
|
||||
ShowMenu();
|
||||
}
|
||||
else
|
||||
{
|
||||
// else hide the iframe
|
||||
frame.style.height = "0px";
|
||||
}
|
||||
});
|
||||
|
||||
// add custom style to iframe
|
||||
frame.classList.add("suggestion-frame");
|
||||
// clear suggestion area to remove the "javascript failed" message
|
||||
ClearSuggestionArea();
|
||||
// collapse the iframe by default
|
||||
frame.style.height = "0px";
|
||||
|
||||
// only execute once (even though multiple iframes exist)
|
||||
if(!parentDoc.hasOwnProperty('keyPhraseSuggestionsInitialized'))
|
||||
{
|
||||
// get parent document head
|
||||
var head = parentDoc.getElementsByTagName('head')[0];
|
||||
// add style tag
|
||||
var s = parentDoc.createElement('style');
|
||||
// set type attribute
|
||||
s.setAttribute('type', 'text/css');
|
||||
// add css forwarded from python
|
||||
if (s.styleSheet) { // IE
|
||||
s.styleSheet.cssText = parentCSS;
|
||||
} else { // the world
|
||||
s.appendChild(parentDoc.createTextNode(parentCSS));
|
||||
}
|
||||
var tooltip = parentDoc.createElement('div');
|
||||
tooltip.id = "phrase-tooltip";
|
||||
parentDoc.body.appendChild(tooltip);
|
||||
parentDoc["phraseTooltip"] = tooltip;
|
||||
// add style to head
|
||||
head.appendChild(s);
|
||||
// set flag so this only runs once
|
||||
parentDoc["keyPhraseSuggestionsInitialized"] = true;
|
||||
}
|
@ -35,7 +35,7 @@ def suggestion_area(placeholder):
|
||||
parent_stylesheet = f.read()
|
||||
|
||||
# add suggestion area div box
|
||||
html = "<div id='suggestion_area'>javascript failed</div>"
|
||||
html = "<div id='scroll_area' class='st-bg'><div id='suggestion_area'>javascript failed</div></div>"
|
||||
# add loaded style
|
||||
html += f"<style>{stylesheet_main}</style>"
|
||||
# set default variables
|
@ -13,13 +13,45 @@ body
|
||||
{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-left: calc( 1em - 1px );
|
||||
padding-top: calc( 1em - 1px );
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#suggestionArea
|
||||
/* width */
|
||||
::-webkit-scrollbar {
|
||||
width: 7px;
|
||||
}
|
||||
|
||||
/* Track */
|
||||
::-webkit-scrollbar-track {
|
||||
background: rgb(10, 13, 19);
|
||||
}
|
||||
|
||||
/* Handle */
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #6c6e72;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* Handle on hover */
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #6c6e72;
|
||||
}
|
||||
|
||||
#scroll_area
|
||||
{
|
||||
display: flex;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#suggestion_area
|
||||
{
|
||||
overflow-x: hidden;
|
||||
width: calc( 100% - 2em - 2px );
|
||||
margin-bottom: calc( 1em + 13px );
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
span
|
1048
scripts/custom_components/sygil_suggestions/main.js
Normal file
1048
scripts/custom_components/sygil_suggestions/main.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,11 @@
|
||||
.suggestion-frame
|
||||
{
|
||||
position: absolute;
|
||||
|
||||
/* make as small as possible */
|
||||
padding: 0px !important;
|
||||
margin: 0px !important;
|
||||
min-height: 0px !important;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
min-height: 0px;
|
||||
line-height: 0;
|
||||
|
||||
/* animate transitions of the height property */
|
||||
@ -11,7 +13,7 @@
|
||||
-moz-transition: height 1s;
|
||||
-ms-transition: height 1s;
|
||||
-o-transition: height 1s;
|
||||
transition: height 1s, y-overflow 300ms;
|
||||
transition: height 1s, border-bottom-width 1s;
|
||||
|
||||
/* block selection */
|
||||
user-select: none;
|
||||
@ -19,6 +21,19 @@
|
||||
-khtml-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-o-user-select: none;
|
||||
|
||||
z-index: 700;
|
||||
|
||||
outline: 1px solid rgba(250, 250, 250, 0.2);
|
||||
outline-offset: 0px;
|
||||
border-radius: 0.25rem;
|
||||
background: rgb(14, 17, 23);
|
||||
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
border-bottom: solid 13px rgb(14, 17, 23) !important;
|
||||
border-left: solid 13px rgb(14, 17, 23) !important;
|
||||
}
|
||||
|
||||
#phrase-tooltip
|
@ -32,7 +32,7 @@ from ldm.models.diffusion.ddim import DDIMSampler
|
||||
from ldm.models.diffusion.plms import PLMSSampler
|
||||
|
||||
# streamlit components
|
||||
from custom_components import key_phrase_suggestions
|
||||
from custom_components import sygil_suggestions
|
||||
|
||||
# Temp imports
|
||||
|
||||
@ -40,7 +40,7 @@ from custom_components import key_phrase_suggestions
|
||||
# end of imports
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
key_phrase_suggestions.init()
|
||||
sygil_suggestions.init()
|
||||
|
||||
try:
|
||||
# this silences the annoying "Some weights of the model checkpoint were not used when initializing..." message at start.
|
||||
@ -372,7 +372,7 @@ def layout():
|
||||
#prompt = st.text_area("Input Text","")
|
||||
placeholder = "A corgi wearing a top hat as an oil painting."
|
||||
prompt = st.text_area("Input Text","", placeholder=placeholder, height=54)
|
||||
key_phrase_suggestions.suggestion_area(placeholder)
|
||||
sygil_suggestions.suggestion_area(placeholder)
|
||||
|
||||
# Every form must have a submit button, the extra blank spaces is a temp way to align it with the input field. Needs to be done in CSS or some other way.
|
||||
img2img_generate_col.write("")
|
||||
|
@ -29,7 +29,7 @@ from ldm.models.diffusion.ddim import DDIMSampler
|
||||
from ldm.models.diffusion.plms import PLMSSampler
|
||||
|
||||
# streamlit components
|
||||
from custom_components import key_phrase_suggestions
|
||||
from custom_components import sygil_suggestions
|
||||
|
||||
# Temp imports
|
||||
|
||||
@ -37,7 +37,7 @@ from custom_components import key_phrase_suggestions
|
||||
# end of imports
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
key_phrase_suggestions.init()
|
||||
sygil_suggestions.init()
|
||||
|
||||
try:
|
||||
# this silences the annoying "Some weights of the model checkpoint were not used when initializing..." message at start.
|
||||
@ -407,7 +407,7 @@ def layout():
|
||||
#prompt = st.text_area("Input Text","")
|
||||
placeholder = "A corgi wearing a top hat as an oil painting."
|
||||
prompt = st.text_area("Input Text","", placeholder=placeholder, height=54)
|
||||
key_phrase_suggestions.suggestion_area(placeholder)
|
||||
sygil_suggestions.suggestion_area(placeholder)
|
||||
|
||||
# creating the page layout using columns
|
||||
col1, col2, col3 = st.columns([1,2,1], gap="large")
|
||||
|
@ -48,14 +48,14 @@ from diffusers.schedulers import DDIMScheduler, LMSDiscreteScheduler, \
|
||||
PNDMScheduler
|
||||
|
||||
# streamlit components
|
||||
from custom_components import key_phrase_suggestions
|
||||
from custom_components import sygil_suggestions
|
||||
|
||||
# Temp imports
|
||||
|
||||
# end of imports
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
key_phrase_suggestions.init()
|
||||
sygil_suggestions.init()
|
||||
|
||||
try:
|
||||
# this silences the annoying "Some weights of the model checkpoint were not used when initializing..." message at start.
|
||||
@ -657,7 +657,7 @@ def layout():
|
||||
#prompt = st.text_area("Input Text","")
|
||||
placeholder = "A corgi wearing a top hat as an oil painting."
|
||||
prompt = st.text_area("Input Text","", placeholder=placeholder, height=54)
|
||||
key_phrase_suggestions.suggestion_area(placeholder)
|
||||
sygil_suggestions.suggestion_area(placeholder)
|
||||
|
||||
# Every form must have a submit button, the extra blank spaces is a temp way to align it with the input field. Needs to be done in CSS or some other way.
|
||||
generate_col1.write("")
|
||||
|
Loading…
Reference in New Issue
Block a user