776 lines
25 KiB
JavaScript
776 lines
25 KiB
JavaScript
import { van } from "./van.js";
|
|
import {
|
|
imageUrl,
|
|
showPreview,
|
|
previewUrl,
|
|
showEditor,
|
|
previewImg,
|
|
previewImgLoading,
|
|
alertDialog,
|
|
isGenerateFlow,
|
|
enableAutoSegment
|
|
} from "./state.js";
|
|
const { button, iframe, div, img, input, label, span, textarea, ul, li } =
|
|
van.tags;
|
|
import { app } from "./app.js";
|
|
import { uploadPreview } from "./index.js";
|
|
import { api } from "./api.js";
|
|
import { uploadSegments } from "./LayerEditor.js";
|
|
import { initModel } from "./onnx.js";
|
|
// import { uploadSegments } from "./LayerEditor.js";
|
|
|
|
const workflowList = [
|
|
"Auto_segment_workflow",
|
|
"BronyaZaychik_(ChinaDress)",
|
|
"BronyaZaychik_(Default_Silverwing)",
|
|
"BronyaZaychik_(Non-official_office_ladysuit)",
|
|
"BronyaZaychik_(Official_office_ladysuit)",
|
|
"BronyaZaychikLora_withhand",
|
|
"SilverWolf_(Default)",
|
|
"SilverWolf_(Maid)",
|
|
];
|
|
|
|
// const workflowList = ["Auto_segment_workflow"];
|
|
/**
|
|
* Load JSON workflow
|
|
* @param {string} name - The name of the workflow to load
|
|
*/
|
|
async function loadJSONWorkflow(name) {
|
|
if (name === 'default' || name.toLowerCase().startsWith("auto_segment")) {
|
|
enableAutoSegment.val = true
|
|
} else {
|
|
enableAutoSegment.val = false
|
|
}
|
|
const json = await (await fetch(`./get_workflow?name=${name}`)).json();
|
|
app.loadGraphData(json);
|
|
console.log(json);
|
|
}
|
|
|
|
async function updatePositivePrompt(app, prompt) {
|
|
const positivePrompt = app.graph
|
|
.findNodesByType("CLIPTextEncode")
|
|
.find((x) => x.color == "#232");
|
|
if (!positivePrompt) {
|
|
alertDialog.val = {
|
|
text: "Cannot find the CLIPTextEncode node. Please make sure the workflow is correct.",
|
|
time: 5000,
|
|
};
|
|
return;
|
|
}
|
|
|
|
positivePrompt.widgets[0].inputEl.value = prompt;
|
|
}
|
|
|
|
async function updateSeedValue(app, seed) {
|
|
const kSampler = app.graph.findNodesByType("KSampler")[0];
|
|
if (!kSampler) {
|
|
alertDialog.val = {
|
|
text: "Cannot find the KSampler node. Please make sure the workflow is correct.",
|
|
time: 5000,
|
|
};
|
|
return;
|
|
}
|
|
kSampler.widgets[0].value = seed;
|
|
kSampler.widgets[1].value = "fixed";
|
|
}
|
|
|
|
async function uploadImage() {
|
|
/** @type {import('../../../web/types/litegraph.js').LGraph}*/
|
|
const graph = app.graph;
|
|
const nodes = graph.findNodesByType("LoadImage");
|
|
previewImgLoading.val = true;
|
|
console.log(previewImgLoading.val);
|
|
|
|
/** @type {any[]}*/
|
|
const widgets = nodes[0].widgets;
|
|
console.log(nodes[0]);
|
|
widgets.find((x) => x.type == "button").callback();
|
|
while (true) {
|
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
if (nodes[0]?.imgs) {
|
|
if (previewImg.val != "" && previewImg.val == nodes[0].imgs[0].currentSrc)
|
|
continue;
|
|
previewImgLoading.val = false;
|
|
return nodes[0].imgs[0].currentSrc;
|
|
}
|
|
}
|
|
}
|
|
|
|
const jsonWorkflowLoading = van.state(true);
|
|
|
|
async function prepareImageFromUrlRedirect(stage) {
|
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
const queue_id = new URLSearchParams(window.location.search).get("queue-id");
|
|
if (queue_id && queue_id != "") {
|
|
console.log(queue_id);
|
|
stage.val = 1;
|
|
const graph = app.graph;
|
|
const node = graph.findNodesByType("LoadImage");
|
|
const imageName = queue_id + ".png";
|
|
console.log(node[0]);
|
|
node[0].widgets_values[0] = imageName;
|
|
node[0].widgets[0].value = imageName;
|
|
node[0].widgets[0]._value = imageName;
|
|
graph.change();
|
|
previewImg.val = api.apiURL(
|
|
`/view?filename=${encodeURIComponent(
|
|
imageName,
|
|
)}&type=input&subfolder=create_avatar_endpoint${app.getPreviewFormatParam()}`,
|
|
);
|
|
console.log(previewImg);
|
|
}
|
|
const dragndrop = document.getElementById("dnd");
|
|
dragndrop.addEventListener("dragenter", (evt) => {
|
|
evt.preventDefault();
|
|
dragndrop.className =
|
|
"h-96 w-full border-2 border-purple-500 text-purple-500 border-dashed rounded-lg flex justify-center items-center";
|
|
});
|
|
dragndrop.addEventListener("dragleave", (evt) => {
|
|
evt.preventDefault();
|
|
dragndrop.className =
|
|
"h-96 w-full border-2 border-black border-dashed items-center rounded-lg flex justify-center";
|
|
});
|
|
dragndrop.addEventListener("dragover", (evt) => {
|
|
evt.preventDefault();
|
|
});
|
|
dragndrop.addEventListener("drop", async (evt) => {
|
|
evt.preventDefault();
|
|
dragndrop.className =
|
|
"h-96 w-full border-2 border-black border-dashed items-center rounded-lg flex justify-center";
|
|
if (evt.dataTransfer.files.length > 1) return;
|
|
if (
|
|
evt.dataTransfer.files[0].type != "image/jpeg" &&
|
|
evt.dataTransfer.files[0].type != "image/png" &&
|
|
evt.dataTransfer.files[0].type != "image/webp"
|
|
)
|
|
return;
|
|
stage.val = 1;
|
|
previewImg.val = URL.createObjectURL(evt.dataTransfer.files[0]);
|
|
if (Object.entries(evt.dataTransfer.files).length) {
|
|
await uploadFile(evt.dataTransfer.files[0], true);
|
|
}
|
|
});
|
|
}
|
|
|
|
export function AvatarPreview() {
|
|
console.log("getting workflow json now");
|
|
loadJSONWorkflow("default").then(() => {
|
|
console.log("done loading");
|
|
jsonWorkflowLoading.val = false;
|
|
});
|
|
|
|
const loading = van.state(false);
|
|
const shareLoading = van.state(false);
|
|
|
|
api.addEventListener("execution_start", (evt) => {
|
|
loading.val = true;
|
|
});
|
|
|
|
api.addEventListener("executed", (evt) => {
|
|
const nodeId = evt.detail.node;
|
|
const targetNode = graph._nodes_by_id[nodeId];
|
|
if (targetNode.type === "AvatarMainOutput") {
|
|
loading.val = false;
|
|
}
|
|
});
|
|
|
|
const email = van.state("");
|
|
const stage = van.state(0); // 0: upload image, 1: edit segment, 2: generate
|
|
|
|
// This will wait 2 seconds until the everything is loaded
|
|
prepareImageFromUrlRedirect(stage);
|
|
|
|
const renderSteps = () => {
|
|
return div(
|
|
{
|
|
class: () =>
|
|
"flex flex-col bg-white justify-center w-[32rem] max-w-[100%]",
|
|
},
|
|
div(
|
|
{
|
|
class: () =>
|
|
" bg-gradient-to-b from-black via-[#5F5F5F] via-60% to-white text-transparent bg-clip-text font-gabarito text-4xl",
|
|
},
|
|
"Avatech v1",
|
|
),
|
|
div(
|
|
{
|
|
class: () =>
|
|
" bg-gradient-to-b from-black via-[#5F5F5F] via-50% to-white text-transparent bg-clip-text font-gabarito text-2xl",
|
|
},
|
|
"Get your DALLE3 AI Personal Clone",
|
|
),
|
|
div(
|
|
{
|
|
class: () =>
|
|
" w-full flex flex-col justify-center items-center gap-4",
|
|
},
|
|
!isGenerateFlow.val
|
|
? div(
|
|
{
|
|
class: () =>
|
|
"flex flex-col justify-center items-center gap-4 w-full",
|
|
},
|
|
div(
|
|
{ class: () => "w-full flex mt-2" },
|
|
button(
|
|
{
|
|
class: () => `btn w-full normal-case`,
|
|
onclick: async () => {
|
|
// previewImg.val = await uploadImage();
|
|
// stage.val = 1;
|
|
var input = document.createElement("input");
|
|
input.type = "file";
|
|
|
|
document.body.appendChild(input);
|
|
|
|
// when the input content changes, do something
|
|
input.onchange = async function (e) {
|
|
stage.val = 1;
|
|
if (Object.entries(e.target.files).length) {
|
|
await uploadFile(e.target.files[0], true);
|
|
}
|
|
previewImg.val = URL.createObjectURL(e.target.files[0]);
|
|
// upload files
|
|
document.body.removeChild(input);
|
|
};
|
|
|
|
// Trigger file browser
|
|
input.click();
|
|
},
|
|
},
|
|
div({ class: "badge badge-neutral" }, "1"),
|
|
div("Upload your image"),
|
|
span({
|
|
class: "iconify text-lg",
|
|
"data-icon": "material-symbols:drive-folder-upload",
|
|
"data-inline": "false",
|
|
}),
|
|
() =>
|
|
previewImgLoading.val
|
|
? span({
|
|
class: "loading loading-spinner loading-md",
|
|
})
|
|
: "",
|
|
),
|
|
),
|
|
() => {
|
|
const dnd = div(
|
|
{
|
|
id: "dnd",
|
|
class: () =>
|
|
"h-96 w-full border-2 border-black border-dashed items-center rounded-lg flex justify-center text-black",
|
|
},
|
|
"or drag and drop the image here",
|
|
);
|
|
const image = img({
|
|
class: () => "z-[10] object-contain w-full h-[394px] border",
|
|
src: previewImg,
|
|
});
|
|
|
|
if (isMobileDevice()) {
|
|
return previewImg.val !== "" ? image : "";
|
|
} else {
|
|
return previewImg.val === "" ? dnd : image;
|
|
}
|
|
},
|
|
button(
|
|
{
|
|
class: () =>
|
|
"btn w-full normal-case " +
|
|
(stage.val < 1 ? "btn-disabled" : ""),
|
|
onclick: () => {
|
|
/** @type {import('../../../web/types/litegraph.js').LGraph}*/
|
|
const graph = app.graph;
|
|
const imageNodes = graph.findNodesByType("LoadImage");
|
|
if (!imageNodes[0].imgs) return;
|
|
|
|
const nodes = graph.findNodesByType("SAM MultiLayer");
|
|
|
|
/** @type {any[]}*/
|
|
const widgets = nodes[0].widgets;
|
|
console.log(nodes[0]);
|
|
console.log(nodes[0].widgets);
|
|
widgets.find((x) => x.type == "button").callback();
|
|
stage.val = 2;
|
|
},
|
|
},
|
|
div({ class: "badge badge-neutral" }, "2"),
|
|
() => enableAutoSegment.val ? "Edit Segment (Auto)" : "Edit Segment",
|
|
),
|
|
button(
|
|
{
|
|
class: () =>
|
|
"btn w-full normal-case " +
|
|
(stage.val < 2 ? "btn-disabled" : ""),
|
|
onclick: async () => {
|
|
// const uploaded = await uploadSegments();
|
|
// if (!uploaded) return;
|
|
|
|
const graph = app.graph;
|
|
const imageNodes = graph.findNodesByType("LoadImage");
|
|
if (!imageNodes[0].imgs) return;
|
|
document.getElementById("queue-button").click();
|
|
},
|
|
},
|
|
div({ class: "badge badge-neutral" }, "3"),
|
|
() =>
|
|
loading.val
|
|
? span({
|
|
class: "loading loading-spinner loading-md",
|
|
})
|
|
: "Make It Alive!",
|
|
),
|
|
)
|
|
: div(
|
|
{
|
|
class:
|
|
"flex flex-col justify-center items-center gap-4 w-full text-black",
|
|
},
|
|
div(
|
|
{
|
|
class:
|
|
"w-full mt-2 flex flex-col rounded-md left-0 top-0",
|
|
},
|
|
textarea({
|
|
class:
|
|
"textarea textarea-bordered border-gray-300 border-b-0 focus:outline-none resize-none rounded-t-md rounded-b-none text-md h-36",
|
|
placeholder: "Enter your prompt",
|
|
defaultValue:
|
|
"1girl, looking at viewer, open mouth, simple background, white background, smile",
|
|
id: "positivePromptProxy",
|
|
}),
|
|
div(
|
|
{
|
|
class:
|
|
"flex flex-row gap-2 border border-gray-300 rounded-b-md text-md items-center",
|
|
},
|
|
span({ class: "ml-4" }, "Seed"),
|
|
div({ class: "divider divider-horizontal m-0" }),
|
|
input({
|
|
type: "text",
|
|
class: "input border-none focus:outline-none w-full p-0",
|
|
placeholder: "Seed",
|
|
defaultValue: "1234",
|
|
id: "seedProxy",
|
|
}),
|
|
div(
|
|
{
|
|
onclick: () => {
|
|
const random4Digits =
|
|
Math.floor(Math.random() * 9000) + 1000;
|
|
console.log(
|
|
random4Digits,
|
|
document.getElementById("seedProxy").value,
|
|
);
|
|
document.getElementById("seedProxy").value =
|
|
random4Digits.toString();
|
|
},
|
|
},
|
|
span({
|
|
class: "iconify text-2xl mr-4 hover:cursor-pointer",
|
|
"data-icon": "fad:random-1dice",
|
|
"data-inline": "false",
|
|
}),
|
|
),
|
|
),
|
|
),
|
|
button(
|
|
{
|
|
class: "btn w-full normal-case ",
|
|
onclick: async () => {
|
|
loading.val = true;
|
|
|
|
updatePositivePrompt(
|
|
app,
|
|
document.getElementById("positivePromptProxy").value,
|
|
);
|
|
updateSeedValue(
|
|
app,
|
|
document.getElementById("seedProxy").value,
|
|
);
|
|
|
|
const sam = app.graph.findNodesByType("SAM MultiLayer")[0];
|
|
if (!sam) {
|
|
alertDialog.val = {
|
|
text: "Cannot find the SAM node. Please make sure the workflow is correct.",
|
|
time: 5000,
|
|
};
|
|
return;
|
|
}
|
|
const ckpt = sam.widgets[0].value;
|
|
const modelType = ckpt.match(/vit_[lbh]/)?.[0];
|
|
await initModel(modelType);
|
|
await uploadSegments();
|
|
|
|
document.getElementById("queue-button").click();
|
|
},
|
|
},
|
|
div({ class: "badge badge-neutral" }, "1"),
|
|
() =>
|
|
loading.val
|
|
? span({ class: "loading loading-spinner loading-md" })
|
|
: "Make It Alive!",
|
|
),
|
|
button(
|
|
{
|
|
class: "btn w-full normal-case",
|
|
onclick: () => {
|
|
/** @type {import('../../../web/types/litegraph.js').LGraph}*/
|
|
const graph = app.graph;
|
|
const nodes = graph.findNodesByType("SAM MultiLayer");
|
|
|
|
/** @type {any[]}*/
|
|
const widgets = nodes[0].widgets;
|
|
console.log(nodes[0]);
|
|
console.log(nodes[0].widgets);
|
|
widgets.find((x) => x.type == "button").callback();
|
|
},
|
|
},
|
|
div({ class: "badge badge-neutral" }, "2"),
|
|
"(Optional) Edit Segment",
|
|
),
|
|
),
|
|
),
|
|
);
|
|
};
|
|
|
|
const renderIFrame = () => {
|
|
return iframe({
|
|
id: "avatech-viewer-iframe",
|
|
title: "avatech-viewer-iframe",
|
|
name: "avatech-viewer-iframe",
|
|
allow: "cross-origin-isolated",
|
|
class: () =>
|
|
"w-full h-full min-w-[300px] min-h-[400px] z-[100] pointer-events-auto flex border-none overflow-hidden" +
|
|
(showPreview.val ? "" : "hidden"),
|
|
// src: "https://labs.avatech.ai/viewer/default",
|
|
// src: "http://localhost:3000/viewer/default",
|
|
src: previewUrl,
|
|
});
|
|
};
|
|
|
|
const renderShareLink = () => {
|
|
return div(
|
|
{
|
|
class: () =>
|
|
"w-full flex flex-col gap-2 justify-center items-center mt-8",
|
|
},
|
|
div(
|
|
{
|
|
class: () =>
|
|
"w-full flex justify-center font-bold italic text-gray-500",
|
|
},
|
|
span("We are launching OpenAI Assistant API integration soon!"),
|
|
),
|
|
div(
|
|
{ class: () => "w-[24rem] flex justify-center items-center" },
|
|
input({
|
|
type: "text",
|
|
class: () =>
|
|
"w-full input input-bordered text-black rounded rounded-l-md rounded-r-none !outline-none",
|
|
onchange: (e) => {
|
|
email.val = e.target.value;
|
|
},
|
|
placeholder: "Enter your email",
|
|
}),
|
|
button(
|
|
{
|
|
class: () =>
|
|
"btn rounded rounded-l-none rounded-r-md no-animation bg-neutral hover:bg-neutral-focus text-white border-none normal-case",
|
|
onclick: async () => {
|
|
shareLoading.val = true;
|
|
const url = await (await fetch("./get_webhook")).json();
|
|
await uploadPreview();
|
|
await fetch(url, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
username: "Avabot",
|
|
avatar_url:
|
|
"https://avatech-avatar-dev1.nyc3.cdn.digitaloceanspaces.com/avatechai.png",
|
|
content: "New register! \n" + email.val,
|
|
}),
|
|
});
|
|
shareLoading.val = false;
|
|
},
|
|
},
|
|
() =>
|
|
shareLoading.val
|
|
? span({
|
|
class: "loading loading-spinner loading-md",
|
|
})
|
|
: "Get Avatar Link",
|
|
),
|
|
),
|
|
);
|
|
};
|
|
|
|
const renderCloseButton = () => {
|
|
return button(
|
|
{
|
|
class: () =>
|
|
"btn flex flex-row btn-ghost text-black normal-case rounded-md left-0 top-0 z-[200] pointer-events-auto sm:btn-md btn-sm ",
|
|
onclick: () => {
|
|
showPreview.val = false;
|
|
},
|
|
},
|
|
span({
|
|
class: "iconify text-lg",
|
|
"data-icon": "ic:round-close",
|
|
"data-inline": "false",
|
|
}),
|
|
);
|
|
};
|
|
|
|
const renderRestartButton = () => {
|
|
return button(
|
|
{
|
|
class: () =>
|
|
"btn flex flex-row btn-ghost text-black normal-case rounded-md left-0 top-0 z-[200] pointer-events-auto sm:btn-md btn-sm ",
|
|
onclick: () => {
|
|
fetch("https://7a49f4ad27be4dcf.ngrok.app/restart");
|
|
},
|
|
},
|
|
span({
|
|
class: "iconify text-lg",
|
|
"data-icon": "mdi:restart",
|
|
"data-inline": "false",
|
|
}),
|
|
);
|
|
};
|
|
|
|
const renderChangeWorkflowButton = () => {
|
|
return div(
|
|
{
|
|
class: () =>
|
|
"dropdown dropdown-hover dropdown-bottom z-[200] pointer-events-auto text-black ",
|
|
},
|
|
label(
|
|
{
|
|
class: () =>
|
|
"btn flex flex-row btn-ghost normal-case rounded-md sm:btn-md btn-sm",
|
|
tabIndex: () => 0,
|
|
},
|
|
span({
|
|
class: "iconify text-lg",
|
|
"data-icon": "ic:round-swap-vert",
|
|
"data-inline": "false",
|
|
}),
|
|
span({ class: "sm:flex hidden" }, () =>
|
|
jsonWorkflowLoading.val ? "Loading" : "Change workflow",
|
|
),
|
|
),
|
|
ul(
|
|
{
|
|
class: () =>
|
|
"dropdown-content -left-[100px] z-[200] menu p-2 shadow rounded-box w-96 bg-white",
|
|
tabIndex: () => 0,
|
|
},
|
|
workflowList.map((val, index) => {
|
|
return li(
|
|
{
|
|
class: () => "p-4 btn btn-ghost items-start",
|
|
onclick: async (e) => {
|
|
e.preventDefault();
|
|
document.activeElement.blur()
|
|
await loadJSONWorkflow(val);
|
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
const kSampler = app.graph.findNodesByType("KSampler")[0];
|
|
if (!kSampler) isGenerateFlow.val = false;
|
|
else isGenerateFlow.val = true;
|
|
},
|
|
},
|
|
() => val,
|
|
);
|
|
}),
|
|
div({ class: () => "divider !my-0" }),
|
|
li(
|
|
{
|
|
class: () => "p-4 btn btn-ghost items-start",
|
|
onclick: (e) => {
|
|
let input = document.createElement("input");
|
|
input.type = "file";
|
|
document.body.appendChild(input);
|
|
input.accept = ".json,image/png,.latent,.safetensors";
|
|
input.onchange = async function (e) {
|
|
if (Object.entries(e.target.files).length) {
|
|
await app.handleFile(e.target.files[0]);
|
|
}
|
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
const kSampler = app.graph.findNodesByType("KSampler")[0];
|
|
if (!kSampler) isGenerateFlow.val = false;
|
|
else isGenerateFlow.val = true;
|
|
document.body.removeChild(input);
|
|
};
|
|
input.click();
|
|
// document.getElementById("comfy-load-button").click();
|
|
},
|
|
},
|
|
"Import...",
|
|
),
|
|
),
|
|
);
|
|
// return button(
|
|
// {
|
|
// class: () =>
|
|
// "btn text-black flex flex-row btn-ghost normal-case rounded-md left-0 top-0 z-[200] pointer-events-auto sm:btn-md btn-sm ",
|
|
// onclick: () => {
|
|
// let input = document.createElement("input");
|
|
// input.type = "file";
|
|
// document.body.appendChild(input);
|
|
// input.accept = ".json,image/png,.latent,.safetensors";
|
|
// input.onchange = async function (e) {
|
|
// if (Object.entries(e.target.files).length) {
|
|
// await app.handleFile(e.target.files[0]);
|
|
// }
|
|
// await new Promise((resolve) => setTimeout(resolve, 200));
|
|
// const kSampler = app.graph.findNodesByType("KSampler")[0];
|
|
// if (!kSampler) isGenerateFlow.val = false;
|
|
// else isGenerateFlow.val = true;
|
|
// document.body.removeChild(input);
|
|
// };
|
|
// input.click();
|
|
// // document.getElementById("comfy-load-button").click();
|
|
// },
|
|
// },
|
|
// span({
|
|
// class: "iconify text-lg",
|
|
// "data-icon": "ic:round-swap-vert",
|
|
// "data-inline": "false",
|
|
// }),
|
|
// span({ class: "sm:flex hidden" }, () =>
|
|
// jsonWorkflowLoading.val ? "Loading" : "Change workflow",
|
|
// ),
|
|
// );
|
|
};
|
|
|
|
const renderTwitter = () => {
|
|
return button(
|
|
{
|
|
class: () =>
|
|
"absolute top-4 right-4 btn sm:w-32 w-20 text-black btn-ghost text-xs z-[200] !px-0 normal-case sm:btn-md btn-sm",
|
|
onclick: () => window.open("https://twitter.com/avatech_gg", "_blank"),
|
|
},
|
|
"Twitter",
|
|
);
|
|
};
|
|
|
|
const isMobileDevice = () => {
|
|
return window.screen.width < 768;
|
|
};
|
|
|
|
return div(
|
|
{
|
|
class: () => {
|
|
console.log(showPreview);
|
|
|
|
return (
|
|
(showPreview.val ? "" : "hidden ") +
|
|
"w-full h-full absolute left-0 top-0 z-[99] pointer-events-auto flex border-none bg-white"
|
|
);
|
|
},
|
|
},
|
|
div(
|
|
{ class: "overflow-y-auto overflow-x-hidden w-full h-full" },
|
|
div(
|
|
{
|
|
class: "absolute top-4 left-4 flex flex-row gap-2",
|
|
},
|
|
renderCloseButton(),
|
|
renderRestartButton(),
|
|
renderChangeWorkflowButton(),
|
|
),
|
|
renderTwitter(),
|
|
() => {
|
|
if (isMobileDevice()) {
|
|
return div(
|
|
{
|
|
class: () =>
|
|
"flex flex-col w-full h-fit bg-white justify-center items-center py-16 px-4 gap-2" +
|
|
(showPreview.val ? "" : "hidden"),
|
|
},
|
|
renderIFrame(),
|
|
renderSteps(),
|
|
renderShareLink(),
|
|
);
|
|
} else {
|
|
return div(
|
|
{
|
|
class: () =>
|
|
"flex w-full h-full bg-white justify-around items-center p-24" +
|
|
(showPreview.val ? "" : "hidden"),
|
|
},
|
|
renderSteps(),
|
|
div(
|
|
{ class: () => "flex flex-col" },
|
|
renderIFrame(),
|
|
renderShareLink(),
|
|
),
|
|
);
|
|
}
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
function showImage(name) {
|
|
const graph = app.graph;
|
|
const node = graph.findNodesByType("LoadImage");
|
|
const img = new Image();
|
|
img.onload = () => {
|
|
node[0].imgs = [img];
|
|
app.graph.setDirtyCanvas(true);
|
|
};
|
|
let folder_separator = name.lastIndexOf("/");
|
|
let subfolder = "";
|
|
if (folder_separator > -1) {
|
|
subfolder = name.substring(0, folder_separator);
|
|
name = name.substring(folder_separator + 1);
|
|
}
|
|
img.src = api.apiURL(
|
|
`/view?filename=${encodeURIComponent(
|
|
name,
|
|
)}&type=input&subfolder=${subfolder}${app.getPreviewFormatParam()}`,
|
|
);
|
|
node.setSizeForImage?.();
|
|
}
|
|
|
|
async function uploadFile(file, updateNode, pasted = false) {
|
|
try {
|
|
// Wrap file in formdata so it includes filename
|
|
const graph = app.graph;
|
|
const nodes = graph.findNodesByType("LoadImage");
|
|
const widgets = nodes[0].widgets.find((w) => w.name === "image");
|
|
const body = new FormData();
|
|
body.append("image", file);
|
|
if (pasted) body.append("subfolder", "pasted");
|
|
const resp = await api.fetchApi("/upload/image", {
|
|
method: "POST",
|
|
body,
|
|
});
|
|
|
|
if (resp.status === 200) {
|
|
const data = await resp.json();
|
|
// Add the file to the dropdown list and update the widget value
|
|
let path = data.name;
|
|
if (data.subfolder) path = data.subfolder + "/" + path;
|
|
|
|
if (!widgets.options.values.includes(path)) {
|
|
widgets.options.values.push(path);
|
|
}
|
|
|
|
if (updateNode) {
|
|
showImage(path);
|
|
widgets.value = path;
|
|
}
|
|
} else {
|
|
alert(resp.status + " - " + resp.statusText);
|
|
}
|
|
} catch (error) {
|
|
alert(error);
|
|
}
|
|
}
|