Files
JaredTherriault-ComfyUI-JNodes/web/js/ImageDrawer/ExtraNetworks.js
T
JaredTherriault cb7f5bc9ca Copy positive_prompt from imageElement, select search text on context change, backend improvements
-Move around some functions to be shared
-Consolidate some text handling
-Select search text when switching contexts
-Add hover menu to imageElements (buttonToolbar)
-Add button to copy 'positive_prompt' value from metadata (use the positive prompt node for compatibility)
-Save metadata to imageElement
-Move some element definitions around in imageElements so functions that rely on certain elements work correctly
2024-01-16 20:10:11 -08:00

358 lines
8.4 KiB
JavaScript

import { api } from "/scripts/api.js";
import { $el } from "/scripts/ui.js";
import { copyToClipboard, setSearchTermsOnElement, createDarkContainer, getDarkColor } from "../common/utils.js"
import { setSearchTextAndExecute } from "./imageDrawer.js";
const NoImagePlaceholder = new URL(`../assets/NoImage.png`, import.meta.url);
let cachedLorasObject = undefined;
/**
* Gets a list of embedding names
* @returns An array of script urls to import
*/
export async function getLoras(bForceRefresh = false) {
if (bForceRefresh || cachedLorasObject == undefined) {
const resp = await api.fetchApi(
'/jnodes_folder_items', { "type": "loras", cache: "no-store" });
const asJson = await resp.json();
//console.log("Size of loras info: " + JSON.stringify(asJson).length)
cachedLorasObject = asJson;
return asJson;
}
return cachedLorasObject;
}
export async function createExtraNetworkCard(loraNameText, familiars) {
if (!loraNameText) {
return;
}
let loraNameToUse = loraNameText;
let trainedWords = [];
let tags = [];
// Load the first image as the object cover image.
// If one does not exist, fall back to placeholder image.
function getHrefForFamiliarImage(index) {
if (familiars?.familiar_images?.length > 0) {
return `/jnodes_view_image?filename=${encodeURIComponent(familiars.familiar_images[index])}&type=${"loras"}`;
}
return NoImagePlaceholder;
}
async function parseFamiliarInfos() {
let infoMap = {};
if (familiars?.familiar_infos?.length > 0) {
for (const familiar_info of familiars.familiar_infos) {
try {
let loadedJson = JSON.parse(familiar_info);
if (loadedJson) {
let jsonKeys = Object.keys(loadedJson);
for (const key of jsonKeys) {
infoMap[key] = loadedJson[key];
}
}
} catch (jsonError) {
console.error(`Error parsing JSON: ${jsonError}`);
}
}
}
if (infoMap['model'] && infoMap['model']['name']) {
loraNameToUse = `${infoMap['model']['name']} (${loraNameToUse})`;
}
if (infoMap['tags']) {
for (const tag of infoMap['tags']) {
tags.push(tag.trim());
}
}
if (infoMap['trainedWords']) {
trainedWords = infoMap['trainedWords'];
}
return infoMap;
}
const infoMap = await parseFamiliarInfos();
function createImageSwitchButton(bIsLeft) {
if (familiars.familiar_images.length < 2) {
return;
}
function onClickLeft(e) {
backgroundImage.lastViewedImageIndex -= 1;
if (backgroundImage.lastViewedImageIndex < 0) {
backgroundImage.lastViewedImageIndex = familiars.familiar_images.length - 1;
}
backgroundImage.src = getHrefForFamiliarImage(backgroundImage.lastViewedImageIndex);
updateImageCounterText();
}
function onClickRight(e) {
backgroundImage.lastViewedImageIndex += 1;
if (backgroundImage.lastViewedImageIndex == familiars.familiar_images.length) {
backgroundImage.lastViewedImageIndex = 0;
}
backgroundImage.src = getHrefForFamiliarImage(backgroundImage.lastViewedImageIndex);
updateImageCounterText();
}
return $el('button', {
style: {
position: "absolute",
top: '50%',
left: bIsLeft ? '5%' : '85%',
transformOrigin: 'center',
fontSize: 'calc(var(--max-size) * 0.02vw)',
},
onclick: bIsLeft ? onClickLeft : onClickRight,
}, [
$el("label", {
textContent: bIsLeft ? "<" : ">",
}),
]);
}
const backgroundImage =
$el("img", {
lastViewedImageIndex: 0,
style: {
objectFit: "cover",
width: "100%",
height: "100%",
}
});
backgroundImage.src = getHrefForFamiliarImage(backgroundImage.lastViewedImageIndex);
let imageCounterLabel;
function updateImageCounterText() {
if (imageCounterLabel) {
if (familiars.familiar_images.length < 1) {
return;
}
const CurrentImageIndex =
parseInt(backgroundImage.lastViewedImageIndex);
imageCounterLabel.textContent =
`${CurrentImageIndex + 1}/${familiars.familiar_images.length}`
}
}
function createImageCounterElement() {
imageCounterLabel = $el("label", {
textContent: 'No preview images found',
});
const imageCounterElement = createDarkContainer();
imageCounterElement.style.top = '2%';
imageCounterElement.style.right = '2%';
imageCounterElement.appendChild(imageCounterLabel);
updateImageCounterText();
return imageCounterElement;
}
function createButtonToolbar() {
function createButtons() {
if (!buttonsRow) { return; }
function createButton(foregroundElement, tooltipText, onClickFunction) {
const buttonElement = $el("button", {
title: tooltipText,
style: {
background: 'none',
border: 'none',
padding: 0,
}
}, [
foregroundElement
]);
buttonElement.addEventListener('click', onClickFunction);
return buttonElement;
}
let copyLoraText = `<lora:${loraNameText}:1:1>`;
if (trainedWords.length > 0) {
//Copy all
let copyAllText = copyLoraText + ", " + trainedWords;
buttonsRow.appendChild(
createButton(
$el("label", {
textContent: "📋",
}),
`Copy lora as a1111-style text + trained words (${copyAllText})`,
function(e) {
copyToClipboard(copyAllText)
e.preventDefault();
}
)
);
// Copy trained words button
buttonsRow.appendChild(
createButton(
$el("label", {
textContent: "📝",
}),
`Copy trained words (${trainedWords})`,
function(e) {
copyToClipboard(trainedWords)
e.preventDefault();
}
)
);
}
// Copy text lora button
buttonsRow.appendChild(
createButton(
$el("label", {
textContent: "📜",
}),
`Copy lora as a1111-style text (${copyLoraText})`,
function(e) {
copyToClipboard(copyLoraText)
e.preventDefault();
}
)
);
}
const buttonsRow = $el("div", {
style: {
width: '100%',
display: 'flex',
flexDirection: 'row',
}
});
const buttonToolbarContainerElement = createDarkContainer();
buttonToolbarContainerElement.style.top = '2%';
buttonToolbarContainerElement.style.left = '2%';
buttonToolbarContainerElement.appendChild(buttonsRow);
createButtons();
return buttonToolbarContainerElement;
}
function createNameAndTagContainer() {
function createTagButton(tagName) {
const buttonElement = $el("button", {
title: `Click to search "${tagName}"`,
style: {
background: 'none',
border: 'none',
padding: '0',
}
}, [
$el("label", {
textContent: tagName,
style: {
fontSize: 'calc(var(--max-size) * 0.01vw)',
color: 'rgb(250,250,250)',
wordBreak: 'keep-all',
}
})
]);
buttonElement.addEventListener('click', () => {
setSearchTextAndExecute(tagName);
});
return buttonElement;
}
const tagButtonContainer = $el("div", {
id: 'tag-container',
style: {
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'center',
gap: '10px',
width: '90%'
}
});
const mainContainer = $el("div", {
id: 'darkened-text-bg',
style: {
position: "absolute",
top: '85%',
left: 0,
width: "100%",
backgroundColor: getDarkColor(),
height: '15%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}
}, [
$el("label", {
textContent: loraNameToUse,
style: {
fontSize: 'calc(var(--max-size) * 0.02vw)',
top: '5%',
wordBreak: 'break-all',
}
}),
tagButtonContainer
]);
for (const tag of tags) {
tagButtonContainer.appendChild(createTagButton(tag));
}
return mainContainer;
}
//console.log("loraNameToUse: " + loraNameToUse);
const loraElement =
$el("div", {
id: "extra-networks-card",
"data-name": loraNameToUse,
style: {
textAlign: 'center',
objectFit: 'var(--div-fit, contain)',
height: 'calc(var(--max-size) * 1vh)',
borderRadius: '4px',
position: "relative",
aspectRatio: '0.67',
},
});
loraElement.appendChild(backgroundImage);
const leftImageSwitchButton = createImageSwitchButton(true);
if (leftImageSwitchButton) { loraElement.appendChild(leftImageSwitchButton); }
const rightImageSwitchButton = createImageSwitchButton(false);
if (rightImageSwitchButton) { loraElement.appendChild(rightImageSwitchButton); }
loraElement.appendChild(createImageCounterElement());
loraElement.appendChild(createButtonToolbar());
loraElement.appendChild(createNameAndTagContainer());
loraElement.title = JSON.stringify(infoMap);
setSearchTermsOnElement(loraElement, `${loraNameToUse}, ${trainedWords}, ${tags.join(', ')}`);
return loraElement;
}