From b3eb1acfacf2f2f59163dc8db9ec5863cbc78efd Mon Sep 17 00:00:00 2001 From: Radionic Date: Wed, 15 Nov 2023 19:22:55 +0800 Subject: [PATCH] feat: lora workflow --- js/AvatarPreview.js | 236 +++++++++++++++++++++++--------------------- js/onnx.js | 8 +- js/tw-styles.css | 186 ++++++++++++++++++++++++---------- 3 files changed, 263 insertions(+), 167 deletions(-) diff --git a/js/AvatarPreview.js b/js/AvatarPreview.js index 432f190..4882843 100644 --- a/js/AvatarPreview.js +++ b/js/AvatarPreview.js @@ -6,11 +6,14 @@ import { showEditor, previewImg, previewImgLoading, + alertDialog, } from "./state.js"; -const { button, iframe, div, img, input, label, span } = van.tags; +const { button, iframe, div, img, input, label, span, textarea } = 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"; async function loadJSONWorkflow() { @@ -59,8 +62,8 @@ async function prepareImageFromUrlRedirect(stage) { graph.change(); previewImg.val = api.apiURL( `/view?filename=${encodeURIComponent( - imageName, - )}&type=input&subfolder=create_avatar_endpoint${app.getPreviewFormatParam()}`, + imageName + )}&type=input&subfolder=create_avatar_endpoint${app.getPreviewFormatParam()}` ); console.log(previewImg); } @@ -131,14 +134,14 @@ export function AvatarPreview() { class: () => " bg-gradient-to-b from-black via-[#5F5F5F] via-60% to-white text-transparent bg-clip-text font-gabarito text-4xl", }, - "Avatech v1", + "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", + "Get your DALLE3 AI Personal Clone" ), // input({ // type: "file", @@ -188,7 +191,9 @@ export function AvatarPreview() { button( { class: () => - `${previewImg.val != "" && 'w-full'} h-full btn flex flex-row normal-case px-4 rounded-md left-0 top-0 z-[200] pointer-events-auto`, + `${ + previewImg.val != "" && "w-full" + } h-full btn flex flex-row normal-case px-4 rounded-md left-0 top-0 z-[200] pointer-events-auto`, onclick: async () => { // previewImg.val = await uploadImage(); // stage.val = 1; @@ -224,10 +229,13 @@ export function AvatarPreview() { ? span({ class: "loading loading-spinner loading-md", }) - : "", + : "" ), previewImg.val == "" - ? div({ class: () => "divider divider-horizontal !gap-0" }, "OR") + ? div( + { class: () => "divider divider-horizontal !gap-0" }, + "OR" + ) : "", previewImg.val == "" ? div( @@ -236,9 +244,9 @@ export function AvatarPreview() { class: () => "w-full border-2 border-black border-dashed items-center rounded-lg flex justify-center", }, - "Drag and drop the image here", + "Drag and drop the image here" ) - : "", + : "" ), () => previewImg.val != "" @@ -271,7 +279,7 @@ export function AvatarPreview() { }, }, div({ class: "badge badge-neutral" }, "2"), - "Edit segment", + "Edit segment" ), button( { @@ -292,84 +300,110 @@ export function AvatarPreview() { () => loading.val ? span({ - class: "loading loading-spinner loading-lg", + class: "loading loading-spinner loading-md", }) - : "Generate", - ), - ), + : "Make it alive!" + ) + ) ), input({ type: "radio", name: "my_tabs_1", - class: () => "tab", + class: "tab", ariaLabel: "Generate avatar", }), div( - { class: () => "tab-content text-black w-full" }, + { class: "tab-content text-black w-full" }, div( - { - class: () => "flex flex-col justify-center items-center gap-4", - }, + { class: "flex flex-col justify-center items-center gap-4" }, + div( + { + class: + "w-full mt-2 flex flex-col rounded-md left-0 top-0 z-[200] flex", + }, + 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", + }) + ) + ), button( { - class: () => - "w-full mt-2 btn flex flex-row normal-case px-4 rounded-md left-0 top-0 z-[200] pointer-events-auto ", + class: "btn w-full normal-case ", onclick: async () => { - // previewImg.val = await uploadImage(); - // stage.val = 1; - var input = document.createElement("input"); - input.type = "file"; + 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; + } + 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; + } - document.body.appendChild(input); + positivePrompt.widgets[0].inputEl.value = + document.getElementById("positivePromptProxy").value; + kSampler.widgets[0].value = + document.getElementById("seedProxy").value; + kSampler.widgets[1].value = "fixed"; - // 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); - }; + loading.val = true; - // Trigger file browser - input.click(); + 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"), - div("Generate 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", - }) - : "", + loading.val + ? span({ class: "loading loading-spinner loading-md" }) + : "Make It Alive!" ), - () => - previewImg.val != "" - ? img({ - class: () => - "z-[10] object-contain w-full h-[394px] border", - src: previewImg, - }) - : "", button( { - class: () => - "btn w-full normal-case " + - (stage.val < 1 ? "btn-disabled" : ""), + class: "btn w-full normal-case", 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[]}*/ @@ -377,39 +411,15 @@ export function AvatarPreview() { 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"), - "Auto 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-lg", - }) - : "Generate", - ), - ), - ), - ), - ), + "(Optional) Edit Segment" + ) + ) + ) + ) + ) ); }; @@ -420,7 +430,7 @@ export function AvatarPreview() { name: "avatech-viewer-iframe", allow: "cross-origin-isolated", class: () => - "w-full h-full min-w-[300px] min-h-[600px] z-[100] pointer-events-auto flex border-none overflow-hidden" + + "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", @@ -439,7 +449,7 @@ export function AvatarPreview() { class: () => "w-full flex justify-center font-bold italic text-gray-500", }, - span("We are launching OpenAI Assistant API integration soon!"), + span("We are launching OpenAI Assistant API integration soon!") ), div( { class: () => "w-[24rem] flex justify-center items-center" }, @@ -478,11 +488,11 @@ export function AvatarPreview() { () => shareLoading.val ? span({ - class: "loading loading-spinner loading-lg", + class: "loading loading-spinner loading-md", }) - : "Get Avatar Link", - ), - ), + : "Get Avatar Link" + ) + ) ); }; @@ -499,7 +509,7 @@ export function AvatarPreview() { class: "iconify text-lg", "data-icon": "ic:round-close", "data-inline": "false", - }), + }) ); }; @@ -516,7 +526,7 @@ export function AvatarPreview() { class: "iconify text-lg", "data-icon": "mdi:restart", "data-inline": "false", - }), + }) ); }; @@ -546,8 +556,8 @@ export function AvatarPreview() { "data-inline": "false", }), span({ class: "sm:flex hidden" }, () => - jsonWorkflowLoading.val ? "Loading" : "Change workflow", - ), + jsonWorkflowLoading.val ? "Loading" : "Change workflow" + ) ); }; @@ -558,7 +568,7 @@ export function AvatarPreview() { "absolute top-4 right-4 btn sm:w-10 w-32 text-black btn-ghost text-xs !px-0 normal-case sm:btn-md btn-sm", onclick: () => window.open("https://twitter.com/avatech_gg", "_blank"), }, - "Twitter", + "Twitter" ); }; @@ -585,7 +595,7 @@ export function AvatarPreview() { }, renderCloseButton(), renderRestartButton(), - renderChangeWorkflowButton(), + renderChangeWorkflowButton() ), renderTwitter(), () => { @@ -598,7 +608,7 @@ export function AvatarPreview() { }, renderIFrame(), renderSteps(), - renderShareLink(), + renderShareLink() ); } else { return div( @@ -611,12 +621,12 @@ export function AvatarPreview() { div( { class: () => "flex flex-col" }, renderIFrame(), - renderShareLink(), - ), + renderShareLink() + ) ); } - }, - ), + } + ) ); } @@ -636,8 +646,8 @@ function showImage(name) { } img.src = api.apiURL( `/view?filename=${encodeURIComponent( - name, - )}&type=input&subfolder=${subfolder}${app.getPreviewFormatParam()}`, + name + )}&type=input&subfolder=${subfolder}${app.getPreviewFormatParam()}` ); node.setSizeForImage?.(); } diff --git a/js/onnx.js b/js/onnx.js index 6dae0ae..c416cfd 100644 --- a/js/onnx.js +++ b/js/onnx.js @@ -10,9 +10,11 @@ export let model = null; // Initialize the ONNX model export const initModel = async (modelType) => { try { - model = await ort.InferenceSession.create( - `${location.protocol}//${location.host}/sam_model?type=${modelType}` - ); + if (!model) { + model = await ort.InferenceSession.create( + `${location.protocol}//${location.host}/sam_model?type=${modelType}` + ); + } } catch (e) { console.log(e); } diff --git a/js/tw-styles.css b/js/tw-styles.css index 0c3d651..6e03c7a 100644 --- a/js/tw-styles.css +++ b/js/tw-styles.css @@ -730,12 +730,6 @@ html{ .tab:hover{ --tw-text-opacity: 1; } - - .tabs-boxed .tab-active:not(.tab-disabled):not([disabled]):hover, - .tabs-boxed :is(input:checked):hover{ - --tw-text-opacity: 1; - color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity))); - } } .btn{ @@ -1388,6 +1382,23 @@ input.tab:checked + .tab-content, display: block; } +.textarea{ + min-height: 3rem; + flex-shrink: 1; + padding-left: 1rem; + padding-right: 1rem; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + font-size: 0.875rem; + line-height: 1.25rem; + line-height: 2; + border-radius: var(--rounded-btn, 0.5rem); + border-width: 1px; + border-color: transparent; + --tw-bg-opacity: 1; + background-color: var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity))); +} + .avatar-group :where(.avatar){ overflow: hidden; border-radius: 9999px; @@ -1522,6 +1533,12 @@ input.tab:checked + .tab-content, } } +.card.bordered{ + border-width: 1px; + --tw-border-opacity: 1; + border-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-border-opacity))); +} + @keyframes checkmark{ 0%{ background-position-y: 5px; @@ -2123,25 +2140,10 @@ details.collapse summary::-webkit-details-marker{ background-position: top right; } -.tabs-boxed{ - border-radius: var(--rounded-btn, 0.5rem); - --tw-bg-opacity: 1; - background-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity))); - padding: 0.25rem; -} - .tabs-boxed .tab{ border-radius: var(--rounded-btn, 0.5rem); } -.tabs-boxed .tab-active:not(.tab-disabled):not([disabled]), - .tabs-boxed :is(input:checked){ - --tw-bg-opacity: 1; - background-color: var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity))); - --tw-text-opacity: 1; - color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity))); -} - .table tr.active, .table tr.active:nth-child(even), .table-zebra tbody tr:nth-child(even){ @@ -2156,6 +2158,42 @@ details.collapse summary::-webkit-details-marker{ background-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity))); } +.textarea-bordered{ + border-color: var(--fallback-bc,oklch(var(--bc)/0.2)); +} + +.textarea:focus{ + box-shadow: none; + border-color: var(--fallback-bc,oklch(var(--bc)/0.2)); + outline-style: solid; + outline-width: 2px; + outline-offset: 2px; + outline-color: var(--fallback-bc,oklch(var(--bc)/0.2)); +} + +.textarea-disabled, + .textarea:disabled, + .textarea[disabled]{ + cursor: not-allowed; + --tw-border-opacity: 1; + border-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-border-opacity))); + --tw-bg-opacity: 1; + background-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity))); + --tw-text-opacity: 0.2; +} + +.textarea-disabled::-moz-placeholder, .textarea:disabled::-moz-placeholder, .textarea[disabled]::-moz-placeholder{ + color: var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity))); + --tw-placeholder-opacity: 0.2; +} + +.textarea-disabled::placeholder, + .textarea:disabled::placeholder, + .textarea[disabled]::placeholder{ + color: var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity))); + --tw-placeholder-opacity: 0.2; +} + @keyframes toast-pop{ 0%{ transform: scale(0.9); @@ -2537,6 +2575,10 @@ details.collapse summary::-webkit-details-marker{ z-index: 99; } +.m-0{ + margin: 0px; +} + .my-0{ margin-top: 0px; margin-bottom: 0px; @@ -2566,6 +2608,10 @@ details.collapse summary::-webkit-details-marker{ margin-top: 2rem; } +.ml-4{ + margin-left: 1rem; +} + .block{ display: block; } @@ -2599,36 +2645,44 @@ details.collapse summary::-webkit-details-marker{ height: 100%; } -.h-\[400px\]{ - height: 400px; -} - .h-24{ height: 6rem; } +.h-36{ + height: 9rem; +} + .min-h-\[600px\]{ min-height: 600px; } -.w-24{ - width: 6rem; +.min-h-\[400px\]{ + min-height: 400px; +} + +.min-h-\[200px\]{ + min-height: 200px; } .w-3{ width: 0.75rem; } +.w-32{ + width: 8rem; +} + .w-56{ width: 14rem; } -.w-96{ +.w-\[24rem\]{ width: 24rem; } -.w-\[24rem\]{ - width: 24rem; +.w-\[32rem\]{ + width: 32rem; } .w-\[550px\]{ @@ -2644,18 +2698,6 @@ details.collapse summary::-webkit-details-marker{ width: 100%; } -.w-\[32rem\]{ - width: 32rem; -} - -.w-32{ - width: 8rem; -} - -.w-\[400px\]{ - width: 400px; -} - .min-w-\[300px\]{ min-width: 300px; } @@ -2678,6 +2720,10 @@ details.collapse summary::-webkit-details-marker{ cursor: pointer; } +.resize-none{ + resize: none; +} + .flex-row{ flex-direction: row; } @@ -2778,6 +2824,26 @@ details.collapse summary::-webkit-details-marker{ border-bottom-right-radius: 0px; } +.rounded-t-md{ + border-top-left-radius: 0.375rem; + border-top-right-radius: 0.375rem; +} + +.rounded-b-none{ + border-bottom-right-radius: 0px; + border-bottom-left-radius: 0px; +} + +.rounded-t-none{ + border-top-left-radius: 0px; + border-top-right-radius: 0px; +} + +.rounded-b-md{ + border-bottom-right-radius: 0.375rem; + border-bottom-left-radius: 0.375rem; +} + .border{ border-width: 1px; } @@ -2790,6 +2856,18 @@ details.collapse summary::-webkit-details-marker{ border-top-width: 4px; } +.border-r{ + border-right-width: 1px; +} + +.border-b-0{ + border-bottom-width: 0px; +} + +.border-t-0{ + border-top-width: 0px; +} + .border-dashed{ border-style: dashed; } @@ -2803,6 +2881,16 @@ details.collapse summary::-webkit-details-marker{ border-color: rgb(249 115 22 / var(--tw-border-opacity)); } +.border-gray-500{ + --tw-border-opacity: 1; + border-color: rgb(107 114 128 / var(--tw-border-opacity)); +} + +.border-gray-300{ + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity)); +} + .border-black{ --tw-border-opacity: 1; border-color: rgb(0 0 0 / var(--tw-border-opacity)); @@ -2909,10 +2997,6 @@ details.collapse summary::-webkit-details-marker{ padding: 0px; } -.p-10{ - padding: 2.5rem; -} - .p-2{ padding: 0.5rem; } @@ -2950,11 +3034,6 @@ details.collapse summary::-webkit-details-marker{ padding-bottom: 0.5rem; } -.py-4{ - padding-top: 1rem; - padding-bottom: 1rem; -} - .text-start{ text-align: start; } @@ -3255,6 +3334,11 @@ img[src] { color: rgb(239 68 68 / var(--tw-text-opacity)); } +.focus\:outline-none:focus{ + outline: 2px solid transparent; + outline-offset: 2px; +} + @media (min-width: 640px){ .sm\:flex{ display: flex;