Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0582d1d869 | ||
|
|
ce073a86c7 | ||
|
|
3a85a1edf2 | ||
|
|
369c1456a9 | ||
|
|
01e323b7e2 | ||
|
|
db684d044a | ||
|
|
8e12803ea1 | ||
|
|
7585d5049a | ||
|
|
772bb09240 | ||
|
|
9a7e18e651 | ||
|
|
a02c8d237f | ||
|
|
2ba5a0ff3d |
@@ -4,12 +4,15 @@ import numpy as np
|
|||||||
import torch
|
import torch
|
||||||
import folder_paths
|
import folder_paths
|
||||||
|
|
||||||
|
|
||||||
class AnyType(str):
|
class AnyType(str):
|
||||||
def __ne__(self, __value: object) -> bool:
|
def __ne__(self, __value: object) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
WILDCARD = AnyType("*")
|
WILDCARD = AnyType("*")
|
||||||
|
|
||||||
|
|
||||||
class ComfyUIDeployExternalLora:
|
class ComfyUIDeployExternalLora:
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
@@ -22,6 +25,10 @@ class ComfyUIDeployExternalLora:
|
|||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
"default_lora_name": (folder_paths.get_filename_list("loras"),),
|
"default_lora_name": (folder_paths.get_filename_list("loras"),),
|
||||||
|
"lora_save_name": ( # if `default_lora_name` is a link to download a file, we will attempt to save it with this name
|
||||||
|
"STRING",
|
||||||
|
{"multiline": False, "default": ""},
|
||||||
|
),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,17 +39,24 @@ class ComfyUIDeployExternalLora:
|
|||||||
|
|
||||||
CATEGORY = "deploy"
|
CATEGORY = "deploy"
|
||||||
|
|
||||||
def run(self, input_id, default_lora_name=None):
|
def run(self, input_id, default_lora_name=None, lora_save_name=None):
|
||||||
import requests
|
import requests
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
if default_lora_name.startswith("http"):
|
if default_lora_name.startswith("http"):
|
||||||
unique_filename = str(uuid.uuid4()) + ".safetensors"
|
if lora_save_name:
|
||||||
print(unique_filename)
|
existing_loras = folder_paths.get_filename_list("loras")
|
||||||
|
# Check if lora_save_name exists in the list
|
||||||
|
if lora_save_name in existing_loras:
|
||||||
|
print(f"using lora: {lora_save_name}")
|
||||||
|
return (lora_save_name,)
|
||||||
|
else:
|
||||||
|
lora_save_name = str(uuid.uuid4()) + ".safetensors"
|
||||||
|
print(lora_save_name)
|
||||||
print(folder_paths.folder_names_and_paths["loras"][0][0])
|
print(folder_paths.folder_names_and_paths["loras"][0][0])
|
||||||
destination_path = os.path.join(
|
destination_path = os.path.join(
|
||||||
folder_paths.folder_names_and_paths["loras"][0][0], unique_filename
|
folder_paths.folder_names_and_paths["loras"][0][0], lora_save_name
|
||||||
)
|
)
|
||||||
print(destination_path)
|
print(destination_path)
|
||||||
print("Downloading external lora - " + input_id + " to " + destination_path)
|
print("Downloading external lora - " + input_id + " to " + destination_path)
|
||||||
@@ -53,7 +67,7 @@ class ComfyUIDeployExternalLora:
|
|||||||
)
|
)
|
||||||
with open(destination_path, "wb") as out_file:
|
with open(destination_path, "wb") as out_file:
|
||||||
out_file.write(response.content)
|
out_file.write(response.content)
|
||||||
return (unique_filename,)
|
return (lora_save_name,)
|
||||||
else:
|
else:
|
||||||
print(f"using lora: {default_lora_name}")
|
print(f"using lora: {default_lora_name}")
|
||||||
return (default_lora_name,)
|
return (default_lora_name,)
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import folder_paths
|
||||||
|
from PIL import Image, ImageOps
|
||||||
|
import numpy as np
|
||||||
|
import torch
|
||||||
|
import json
|
||||||
|
|
||||||
|
class ComfyUIDeployExternalTextList:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"input_id": (
|
||||||
|
"STRING",
|
||||||
|
{"multiline": False, "default": 'input_text_list'},
|
||||||
|
),
|
||||||
|
"text": (
|
||||||
|
"STRING",
|
||||||
|
{"multiline": True, "default": "[]"},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = ("STRING",)
|
||||||
|
RETURN_NAMES = ("text",)
|
||||||
|
|
||||||
|
OUTPUT_IS_LIST = (True,)
|
||||||
|
|
||||||
|
FUNCTION = "run"
|
||||||
|
|
||||||
|
CATEGORY = "text"
|
||||||
|
|
||||||
|
def run(self, input_id, text=None):
|
||||||
|
text_list = []
|
||||||
|
try:
|
||||||
|
text_list = json.loads(text) # Assuming text is a JSON array string
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error processing images: {e}")
|
||||||
|
pass
|
||||||
|
return [text_list]
|
||||||
|
|
||||||
|
|
||||||
|
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalTextList": ComfyUIDeployExternalTextList}
|
||||||
|
NODE_DISPLAY_NAME_MAPPINGS = {"ComfyUIDeployExternalTextList": "External Text List (ComfyUI Deploy)"}
|
||||||
+6
-5
@@ -108,7 +108,8 @@ def log_span(name):
|
|||||||
if use_logfire:
|
if use_logfire:
|
||||||
with logger.span(name):
|
with logger.span(name):
|
||||||
yield
|
yield
|
||||||
# else:
|
else:
|
||||||
|
yield
|
||||||
# logger.info(f"Start: {name}")
|
# logger.info(f"Start: {name}")
|
||||||
# yield
|
# yield
|
||||||
# logger.info(f"End: {name}")
|
# logger.info(f"End: {name}")
|
||||||
@@ -348,7 +349,7 @@ async def comfy_deploy_run(request):
|
|||||||
|
|
||||||
status = 200
|
status = 200
|
||||||
|
|
||||||
if "node_errors" in res and res["node_errors"]:
|
if "node_errors" in res and res["node_errors"] is not None:
|
||||||
# Even tho there are node_errors it can still be run
|
# Even tho there are node_errors it can still be run
|
||||||
status = 400
|
status = 400
|
||||||
await update_run_with_output(prompt_id, {
|
await update_run_with_output(prompt_id, {
|
||||||
@@ -386,7 +387,7 @@ async def stream_prompt(data):
|
|||||||
workflow_api=workflow_api
|
workflow_api=workflow_api
|
||||||
)
|
)
|
||||||
|
|
||||||
log('info', "Begin prompt", prompt=prompt)
|
# log('info', "Begin prompt", prompt=prompt)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
res = post_prompt(prompt)
|
res = post_prompt(prompt)
|
||||||
@@ -409,7 +410,7 @@ async def stream_prompt(data):
|
|||||||
|
|
||||||
status = 200
|
status = 200
|
||||||
|
|
||||||
if "node_errors" in res and res["node_errors"]:
|
if "node_errors" in res and res["node_errors"] is not None:
|
||||||
# Even tho there are node_errors it can still be run
|
# Even tho there are node_errors it can still be run
|
||||||
status = 400
|
status = 400
|
||||||
await update_run_with_output(prompt_id, {
|
await update_run_with_output(prompt_id, {
|
||||||
@@ -453,7 +454,7 @@ async def stream_response(request):
|
|||||||
if not comfy_message_queues[prompt_id].empty():
|
if not comfy_message_queues[prompt_id].empty():
|
||||||
data = await comfy_message_queues[prompt_id].get()
|
data = await comfy_message_queues[prompt_id].get()
|
||||||
|
|
||||||
log('info', data["event"], data=json.dumps(data))
|
# log('info', data["event"], data=json.dumps(data))
|
||||||
# logger.info("listener", data)
|
# logger.info("listener", data)
|
||||||
await response.write(f"event: event_update\ndata: {json.dumps(data)}\n\n".encode('utf-8'))
|
await response.write(f"event: event_update\ndata: {json.dumps(data)}\n\n".encode('utf-8'))
|
||||||
await response.drain() # Ensure the buffer is flushed
|
await response.drain() # Ensure the buffer is flushed
|
||||||
|
|||||||
+192
-57
@@ -24,7 +24,10 @@ function dispatchAPIEventData(data) {
|
|||||||
message += "\n" + nodeError.class_type + ":";
|
message += "\n" + nodeError.class_type + ":";
|
||||||
for (const errorReason of nodeError.errors) {
|
for (const errorReason of nodeError.errors) {
|
||||||
message +=
|
message +=
|
||||||
"\n - " + errorReason.message + ": " + errorReason.details;
|
"\n - " +
|
||||||
|
errorReason.message +
|
||||||
|
": " +
|
||||||
|
errorReason.details;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,32 +47,38 @@ function dispatchAPIEventData(data) {
|
|||||||
// window.name = this.clientId; // use window name so it isnt reused when duplicating tabs
|
// window.name = this.clientId; // use window name so it isnt reused when duplicating tabs
|
||||||
// sessionStorage.setItem("clientId", this.clientId); // store in session storage so duplicate tab can load correct workflow
|
// sessionStorage.setItem("clientId", this.clientId); // store in session storage so duplicate tab can load correct workflow
|
||||||
}
|
}
|
||||||
api.dispatchEvent(new CustomEvent("status", { detail: msg.data.status }));
|
api.dispatchEvent(
|
||||||
|
new CustomEvent("status", { detail: msg.data.status })
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case "progress":
|
case "progress":
|
||||||
api.dispatchEvent(new CustomEvent("progress", { detail: msg.data }));
|
api.dispatchEvent(
|
||||||
|
new CustomEvent("progress", { detail: msg.data })
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case "executing":
|
case "executing":
|
||||||
api.dispatchEvent(
|
api.dispatchEvent(
|
||||||
new CustomEvent("executing", { detail: msg.data.node }),
|
new CustomEvent("executing", { detail: msg.data.node })
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "executed":
|
case "executed":
|
||||||
api.dispatchEvent(new CustomEvent("executed", { detail: msg.data }));
|
api.dispatchEvent(
|
||||||
|
new CustomEvent("executed", { detail: msg.data })
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case "execution_start":
|
case "execution_start":
|
||||||
api.dispatchEvent(
|
api.dispatchEvent(
|
||||||
new CustomEvent("execution_start", { detail: msg.data }),
|
new CustomEvent("execution_start", { detail: msg.data })
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "execution_error":
|
case "execution_error":
|
||||||
api.dispatchEvent(
|
api.dispatchEvent(
|
||||||
new CustomEvent("execution_error", { detail: msg.data }),
|
new CustomEvent("execution_error", { detail: msg.data })
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "execution_cached":
|
case "execution_cached":
|
||||||
api.dispatchEvent(
|
api.dispatchEvent(
|
||||||
new CustomEvent("execution_cached", { detail: msg.data }),
|
new CustomEvent("execution_cached", { detail: msg.data })
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -143,11 +152,13 @@ const ext = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!workflow_version_id) {
|
if (!workflow_version_id) {
|
||||||
console.error("No workflow_version_id provided in query parameters.");
|
console.error(
|
||||||
|
"No workflow_version_id provided in query parameters."
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
loadingDialog.showLoading(
|
loadingDialog.showLoading(
|
||||||
"Loading workflow from " + org_display,
|
"Loading workflow from " + org_display,
|
||||||
"Please wait...",
|
"Please wait..."
|
||||||
);
|
);
|
||||||
fetch(endpoint + "/api/workflow-version/" + workflow_version_id, {
|
fetch(endpoint + "/api/workflow-version/" + workflow_version_id, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
@@ -160,7 +171,10 @@ const ext = {
|
|||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const { workflow, workflow_id, error } = data;
|
const { workflow, workflow_id, error } = data;
|
||||||
if (error) {
|
if (error) {
|
||||||
infoDialog.showMessage("Unable to load this workflow", error);
|
infoDialog.showMessage(
|
||||||
|
"Unable to load this workflow",
|
||||||
|
error
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +197,7 @@ const ext = {
|
|||||||
window.history.replaceState(
|
window.history.replaceState(
|
||||||
{},
|
{},
|
||||||
document.title,
|
document.title,
|
||||||
window.location.pathname,
|
window.location.pathname
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -206,22 +220,37 @@ const ext = {
|
|||||||
ComfyWidgets.STRING(
|
ComfyWidgets.STRING(
|
||||||
this,
|
this,
|
||||||
"workflow_name",
|
"workflow_name",
|
||||||
["", { default: this.properties.workflow_name, multiline: false }],
|
[
|
||||||
app,
|
"",
|
||||||
|
{
|
||||||
|
default: this.properties.workflow_name,
|
||||||
|
multiline: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
app
|
||||||
);
|
);
|
||||||
|
|
||||||
ComfyWidgets.STRING(
|
ComfyWidgets.STRING(
|
||||||
this,
|
this,
|
||||||
"workflow_id",
|
"workflow_id",
|
||||||
["", { default: this.properties.workflow_id, multiline: false }],
|
[
|
||||||
app,
|
"",
|
||||||
|
{
|
||||||
|
default: this.properties.workflow_id,
|
||||||
|
multiline: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
app
|
||||||
);
|
);
|
||||||
|
|
||||||
ComfyWidgets.STRING(
|
ComfyWidgets.STRING(
|
||||||
this,
|
this,
|
||||||
"version",
|
"version",
|
||||||
["", { default: this.properties.version, multiline: false }],
|
[
|
||||||
app,
|
"",
|
||||||
|
{ default: this.properties.version, multiline: false },
|
||||||
|
],
|
||||||
|
app
|
||||||
);
|
);
|
||||||
|
|
||||||
// this.widgets.forEach((w) => {
|
// this.widgets.forEach((w) => {
|
||||||
@@ -248,7 +277,7 @@ const ext = {
|
|||||||
title_mode: LiteGraph.NORMAL_TITLE,
|
title_mode: LiteGraph.NORMAL_TITLE,
|
||||||
title: "Comfy Deploy",
|
title: "Comfy Deploy",
|
||||||
collapsable: true,
|
collapsable: true,
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
ComfyDeploy.category = "deploy";
|
ComfyDeploy.category = "deploy";
|
||||||
@@ -278,7 +307,13 @@ const ext = {
|
|||||||
sendEventToCD("cd_plugin_onDeployChanges", prompt);
|
sendEventToCD("cd_plugin_onDeployChanges", prompt);
|
||||||
} else if (message.type === "queue_prompt") {
|
} else if (message.type === "queue_prompt") {
|
||||||
const prompt = await app.graphToPrompt();
|
const prompt = await app.graphToPrompt();
|
||||||
|
if (typeof api.handlePromptGenerated === "function") {
|
||||||
api.handlePromptGenerated(prompt);
|
api.handlePromptGenerated(prompt);
|
||||||
|
} else {
|
||||||
|
console.warn(
|
||||||
|
"api.handlePromptGenerated is not a function"
|
||||||
|
);
|
||||||
|
}
|
||||||
sendEventToCD("cd_plugin_onQueuePrompt", prompt);
|
sendEventToCD("cd_plugin_onQueuePrompt", prompt);
|
||||||
} else if (message.type === "get_prompt") {
|
} else if (message.type === "get_prompt") {
|
||||||
const prompt = await app.graphToPrompt();
|
const prompt = await app.graphToPrompt();
|
||||||
@@ -301,6 +336,72 @@ const ext = {
|
|||||||
|
|
||||||
app.graph.add(node);
|
app.graph.add(node);
|
||||||
app.graph.afterChange();
|
app.graph.afterChange();
|
||||||
|
} else if (message.type === "zoom_to_node") {
|
||||||
|
const nodeId = message.data.nodeId;
|
||||||
|
const position = message.data.position;
|
||||||
|
|
||||||
|
const node = app.graph.getNodeById(nodeId);
|
||||||
|
if (!node) return;
|
||||||
|
|
||||||
|
const canvas = app.canvas;
|
||||||
|
const targetScale = 1;
|
||||||
|
const targetOffsetX =
|
||||||
|
canvas.canvas.width / 4 -
|
||||||
|
position[0] -
|
||||||
|
node.size[0] / 2;
|
||||||
|
const targetOffsetY =
|
||||||
|
canvas.canvas.height / 4 -
|
||||||
|
position[1] -
|
||||||
|
node.size[1] / 2;
|
||||||
|
|
||||||
|
const startScale = canvas.ds.scale;
|
||||||
|
const startOffsetX = canvas.ds.offset[0];
|
||||||
|
const startOffsetY = canvas.ds.offset[1];
|
||||||
|
|
||||||
|
const duration = 400; // Animation duration in milliseconds
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
function easeOutCubic(t) {
|
||||||
|
return 1 - Math.pow(1 - t, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
function lerp(start, end, t) {
|
||||||
|
return start * (1 - t) + end * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
function animate() {
|
||||||
|
const currentTime = Date.now();
|
||||||
|
const elapsedTime = currentTime - startTime;
|
||||||
|
const t = Math.min(elapsedTime / duration, 1);
|
||||||
|
|
||||||
|
const easedT = easeOutCubic(t);
|
||||||
|
|
||||||
|
const currentScale = lerp(
|
||||||
|
startScale,
|
||||||
|
targetScale,
|
||||||
|
easedT
|
||||||
|
);
|
||||||
|
const currentOffsetX = lerp(
|
||||||
|
startOffsetX,
|
||||||
|
targetOffsetX,
|
||||||
|
easedT
|
||||||
|
);
|
||||||
|
const currentOffsetY = lerp(
|
||||||
|
startOffsetY,
|
||||||
|
targetOffsetY,
|
||||||
|
easedT
|
||||||
|
);
|
||||||
|
|
||||||
|
canvas.setZoom(currentScale);
|
||||||
|
canvas.ds.offset = [currentOffsetX, currentOffsetY];
|
||||||
|
canvas.draw(true, true);
|
||||||
|
|
||||||
|
if (t < 1) {
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
animate();
|
||||||
}
|
}
|
||||||
// else if (message.type === "refresh") {
|
// else if (message.type === "refresh") {
|
||||||
// sendEventToCD("cd_plugin_onRefresh");
|
// sendEventToCD("cd_plugin_onRefresh");
|
||||||
@@ -341,7 +442,7 @@ const ext = {
|
|||||||
|
|
||||||
function showError(title, message) {
|
function showError(title, message) {
|
||||||
infoDialog.show(
|
infoDialog.show(
|
||||||
`<h3 style="margin: 0px; color: red;">${title}</h3><br><span>${message}</span> `,
|
`<h3 style="margin: 0px; color: red;">${title}</h3><br><span>${message}</span> `
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,11 +476,14 @@ function createDynamicUIHtml(data) {
|
|||||||
Object.values(data.custom_nodes).forEach((node) => {
|
Object.values(data.custom_nodes).forEach((node) => {
|
||||||
html += `
|
html += `
|
||||||
<div style="border-bottom: 1px solid #e2e8f0; padding-top: 16px;">
|
<div style="border-bottom: 1px solid #e2e8f0; padding-top: 16px;">
|
||||||
<a href="${node.url
|
<a href="${
|
||||||
}" target="_blank" style="font-size: 18px; font-weight: semibold; color: white; text-decoration: none;">${node.name
|
node.url
|
||||||
|
}" target="_blank" style="font-size: 18px; font-weight: semibold; color: white; text-decoration: none;">${
|
||||||
|
node.name
|
||||||
}</a>
|
}</a>
|
||||||
<p style="font-size: 14px; color: #4b5563;">${node.hash}</p>
|
<p style="font-size: 14px; color: #4b5563;">${node.hash}</p>
|
||||||
${node.warning
|
${
|
||||||
|
node.warning
|
||||||
? `<p style="font-size: 14px; color: #d69e2e;">${node.warning}</p>`
|
? `<p style="font-size: 14px; color: #d69e2e;">${node.warning}</p>`
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
@@ -396,7 +500,8 @@ function createDynamicUIHtml(data) {
|
|||||||
Object.entries(data.models).forEach(([section, items]) => {
|
Object.entries(data.models).forEach(([section, items]) => {
|
||||||
html += `
|
html += `
|
||||||
<div style="border-bottom: 1px solid #e2e8f0; padding-top: 8px; padding-bottom: 8px;">
|
<div style="border-bottom: 1px solid #e2e8f0; padding-top: 8px; padding-bottom: 8px;">
|
||||||
<h3 style="font-size: 18px; font-weight: semibold; margin-bottom: 8px;">${section.charAt(0).toUpperCase() + section.slice(1)
|
<h3 style="font-size: 18px; font-weight: semibold; margin-bottom: 8px;">${
|
||||||
|
section.charAt(0).toUpperCase() + section.slice(1)
|
||||||
}</h3>`;
|
}</h3>`;
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
html += `<p style="font-size: 14px; color: ${textColor};">${item.name}</p>`;
|
html += `<p style="font-size: 14px; color: ${textColor};">${item.name}</p>`;
|
||||||
@@ -413,7 +518,8 @@ function createDynamicUIHtml(data) {
|
|||||||
Object.entries(data.files).forEach(([section, items]) => {
|
Object.entries(data.files).forEach(([section, items]) => {
|
||||||
html += `
|
html += `
|
||||||
<div style="border-bottom: 1px solid #e2e8f0; padding-top: 8px; padding-bottom: 8px;">
|
<div style="border-bottom: 1px solid #e2e8f0; padding-top: 8px; padding-bottom: 8px;">
|
||||||
<h3 style="font-size: 18px; font-weight: semibold; margin-bottom: 8px;">${section.charAt(0).toUpperCase() + section.slice(1)
|
<h3 style="font-size: 18px; font-weight: semibold; margin-bottom: 8px;">${
|
||||||
|
section.charAt(0).toUpperCase() + section.slice(1)
|
||||||
}</h3>`;
|
}</h3>`;
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
html += `<p style="font-size: 14px; color: ${textColor};">${item.name}</p>`;
|
html += `<p style="font-size: 14px; color: ${textColor};">${item.name}</p>`;
|
||||||
@@ -444,7 +550,7 @@ async function deployWorkflow() {
|
|||||||
if (deployMeta.length == 0) {
|
if (deployMeta.length == 0) {
|
||||||
const text = await inputDialog.input(
|
const text = await inputDialog.input(
|
||||||
"Create your deployment",
|
"Create your deployment",
|
||||||
"Workflow name",
|
"Workflow name"
|
||||||
);
|
);
|
||||||
if (!text) return;
|
if (!text) return;
|
||||||
console.log(text);
|
console.log(text);
|
||||||
@@ -485,7 +591,7 @@ async function deployWorkflow() {
|
|||||||
<input id="reuse-hash" type="checkbox" checked>Reuse hash from last version</input>
|
<input id="reuse-hash" type="checkbox" checked>Reuse hash from last version</input>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`
|
||||||
);
|
);
|
||||||
if (!ok) return;
|
if (!ok) return;
|
||||||
|
|
||||||
@@ -504,7 +610,7 @@ async function deployWorkflow() {
|
|||||||
if (!snapshot) {
|
if (!snapshot) {
|
||||||
showError(
|
showError(
|
||||||
"Error when deploying",
|
"Error when deploying",
|
||||||
"Unable to generate snapshot, please install ComfyUI Manager",
|
"Unable to generate snapshot, please install ComfyUI Manager"
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -525,7 +631,7 @@ async function deployWorkflow() {
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: "Bearer " + apiKey,
|
Authorization: "Bearer " + apiKey,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
)
|
)
|
||||||
.then((x) => x.json())
|
.then((x) => x.json())
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
@@ -544,7 +650,7 @@ async function deployWorkflow() {
|
|||||||
// Match previous hash for models
|
// Match previous hash for models
|
||||||
if (reuseHash && existing_workflow?.dependencies?.models) {
|
if (reuseHash && existing_workflow?.dependencies?.models) {
|
||||||
const previousModelHash = Object.entries(
|
const previousModelHash = Object.entries(
|
||||||
existing_workflow?.dependencies?.models,
|
existing_workflow?.dependencies?.models
|
||||||
).flatMap(([key, value]) => {
|
).flatMap(([key, value]) => {
|
||||||
return Object.values(value).map((x) => ({
|
return Object.values(value).map((x) => ({
|
||||||
...x,
|
...x,
|
||||||
@@ -566,7 +672,9 @@ async function deployWorkflow() {
|
|||||||
console.log(file);
|
console.log(file);
|
||||||
loadingDialog.showLoading("Generating hash", file);
|
loadingDialog.showLoading("Generating hash", file);
|
||||||
const hash = await fetch(
|
const hash = await fetch(
|
||||||
`/comfyui-deploy/get-file-hash?file_path=${encodeURIComponent(file)}`,
|
`/comfyui-deploy/get-file-hash?file_path=${encodeURIComponent(
|
||||||
|
file
|
||||||
|
)}`
|
||||||
).then((x) => x.json());
|
).then((x) => x.json());
|
||||||
loadingDialog.showLoading("Generating hash", file);
|
loadingDialog.showLoading("Generating hash", file);
|
||||||
console.log(hash);
|
console.log(hash);
|
||||||
@@ -576,18 +684,24 @@ async function deployWorkflow() {
|
|||||||
console.log("Uploading ", file);
|
console.log("Uploading ", file);
|
||||||
loadingDialog.showLoading("Uploading file", file);
|
loadingDialog.showLoading("Uploading file", file);
|
||||||
try {
|
try {
|
||||||
const { download_url } = await fetch(`/comfyui-deploy/upload-file`, {
|
const { download_url } = await fetch(
|
||||||
|
`/comfyui-deploy/upload-file`,
|
||||||
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
file_path: file,
|
file_path: file,
|
||||||
token: apiKey,
|
token: apiKey,
|
||||||
url: endpoint + "/api/upload-url",
|
url: endpoint + "/api/upload-url",
|
||||||
}),
|
}),
|
||||||
})
|
}
|
||||||
|
)
|
||||||
.then((x) => x.json())
|
.then((x) => x.json())
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
loadingDialog.close();
|
loadingDialog.close();
|
||||||
confirmDialog.confirm("Error", "Unable to upload file " + file);
|
confirmDialog.confirm(
|
||||||
|
"Error",
|
||||||
|
"Unable to upload file " + file
|
||||||
|
);
|
||||||
});
|
});
|
||||||
loadingDialog.showLoading("Uploaded file", file);
|
loadingDialog.showLoading("Uploaded file", file);
|
||||||
console.log(download_url);
|
console.log(download_url);
|
||||||
@@ -624,8 +738,8 @@ async function deployWorkflow() {
|
|||||||
<iframe
|
<iframe
|
||||||
style="z-index: 10; min-width: 600px; max-width: 1024px; min-height: 600px; border: none; background-color: transparent;"
|
style="z-index: 10; min-width: 600px; max-width: 1024px; min-height: 600px; border: none; background-color: transparent;"
|
||||||
src="https://www.comfydeploy.com/dependency-graph?deps=${encodeURIComponent(
|
src="https://www.comfydeploy.com/dependency-graph?deps=${encodeURIComponent(
|
||||||
JSON.stringify(deps),
|
JSON.stringify(deps)
|
||||||
)}" />`,
|
)}" />`
|
||||||
// createDynamicUIHtml(deps),
|
// createDynamicUIHtml(deps),
|
||||||
);
|
);
|
||||||
if (!depsOk) return;
|
if (!depsOk) return;
|
||||||
@@ -686,7 +800,7 @@ async function deployWorkflow() {
|
|||||||
graph.change();
|
graph.change();
|
||||||
|
|
||||||
infoDialog.show(
|
infoDialog.show(
|
||||||
`<span style="color:green;">Deployed successfully!</span> <a style="color:white;" target="_blank" href=${endpoint}/workflows/${data.workflow_id}>-> View here</a> <br/> <br/> Workflow ID: ${data.workflow_id} <br/> Workflow Name: ${workflow_name} <br/> Workflow Version: ${data.version} <br/>`,
|
`<span style="color:green;">Deployed successfully!</span> <a style="color:white;" target="_blank" href=${endpoint}/workflows/${data.workflow_id}>-> View here</a> <br/> <br/> Workflow ID: ${data.workflow_id} <br/> Workflow Name: ${workflow_name} <br/> Workflow Version: ${data.version} <br/>`
|
||||||
);
|
);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -837,9 +951,11 @@ export class LoadingDialog extends ComfyDialog {
|
|||||||
showLoading(title, message) {
|
showLoading(title, message) {
|
||||||
this.show(`
|
this.show(`
|
||||||
<div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
<div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
||||||
<h3 style="margin: 0px; display: flex; align-items: center; justify-content: center; gap: 12px;">${title} ${this.loadingIcon
|
<h3 style="margin: 0px; display: flex; align-items: center; justify-content: center; gap: 12px;">${title} ${
|
||||||
|
this.loadingIcon
|
||||||
}</h3>
|
}</h3>
|
||||||
${message
|
${
|
||||||
|
message
|
||||||
? `<label style="max-width: 100%; white-space: pre-wrap; word-wrap: break-word;">${message}</label>`
|
? `<label style="max-width: 100%; white-space: pre-wrap; word-wrap: break-word;">${message}</label>`
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
@@ -881,17 +997,22 @@ export class InputDialog extends InfoDialog {
|
|||||||
type: "button",
|
type: "button",
|
||||||
textContent: "Save",
|
textContent: "Save",
|
||||||
onclick: () => {
|
onclick: () => {
|
||||||
const input = this.textElement.querySelector("#input").value;
|
const input =
|
||||||
|
this.textElement.querySelector("#input").value;
|
||||||
if (input.trim() === "") {
|
if (input.trim() === "") {
|
||||||
showError("Input validation", "Input cannot be empty");
|
showError(
|
||||||
|
"Input validation",
|
||||||
|
"Input cannot be empty"
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
this.callback?.(input);
|
this.callback?.(input);
|
||||||
this.close();
|
this.close();
|
||||||
this.textElement.querySelector("#input").value = "";
|
this.textElement.querySelector("#input").value =
|
||||||
|
"";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
]
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -952,7 +1073,7 @@ export class ConfirmDialog extends InfoDialog {
|
|||||||
this.close();
|
this.close();
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
]
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -1009,7 +1130,7 @@ function getData(environment) {
|
|||||||
function saveData(data) {
|
function saveData(data) {
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"comfy_deploy_env_data_" + data.environment,
|
"comfy_deploy_env_data_" + data.environment,
|
||||||
JSON.stringify(data),
|
JSON.stringify(data)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1024,7 +1145,9 @@ export class ConfigDialog extends ComfyDialog {
|
|||||||
this.element.style.paddingBottom = "20px";
|
this.element.style.paddingBottom = "20px";
|
||||||
|
|
||||||
this.container = document.createElement("div");
|
this.container = document.createElement("div");
|
||||||
this.element.querySelector(".comfy-modal-content").prepend(this.container);
|
this.element
|
||||||
|
.querySelector(".comfy-modal-content")
|
||||||
|
.prepend(this.container);
|
||||||
}
|
}
|
||||||
|
|
||||||
createButtons() {
|
createButtons() {
|
||||||
@@ -1058,7 +1181,7 @@ export class ConfigDialog extends ComfyDialog {
|
|||||||
this.close();
|
this.close();
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
]
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -1070,7 +1193,8 @@ export class ConfigDialog extends ComfyDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
save(api_key, displayName) {
|
save(api_key, displayName) {
|
||||||
const deployOption = this.container.querySelector("#deployOption").value;
|
const deployOption =
|
||||||
|
this.container.querySelector("#deployOption").value;
|
||||||
localStorage.setItem("comfy_deploy_env", deployOption);
|
localStorage.setItem("comfy_deploy_env", deployOption);
|
||||||
|
|
||||||
const endpoint = this.container.querySelector("#endpoint").value;
|
const endpoint = this.container.querySelector("#endpoint").value;
|
||||||
@@ -1102,22 +1226,32 @@ export class ConfigDialog extends ComfyDialog {
|
|||||||
<h3 style="margin: 0px;">Comfy Deploy Config</h3>
|
<h3 style="margin: 0px;">Comfy Deploy Config</h3>
|
||||||
<label style="color: white; width: 100%;">
|
<label style="color: white; width: 100%;">
|
||||||
<select id="deployOption" style="margin: 8px 0px; width: 100%; height:30px; box-sizing: border-box;" >
|
<select id="deployOption" style="margin: 8px 0px; width: 100%; height:30px; box-sizing: border-box;" >
|
||||||
<option value="cloud" ${data.environment === "cloud" ? "selected" : ""}>Cloud</option>
|
<option value="cloud" ${
|
||||||
<option value="local" ${data.environment === "local" ? "selected" : ""}>Local</option>
|
data.environment === "cloud" ? "selected" : ""
|
||||||
|
}>Cloud</option>
|
||||||
|
<option value="local" ${
|
||||||
|
data.environment === "local" ? "selected" : ""
|
||||||
|
}>Local</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label style="color: white; width: 100%;">
|
<label style="color: white; width: 100%;">
|
||||||
Endpoint:
|
Endpoint:
|
||||||
<input id="endpoint" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;" type="text" value="${data.endpoint
|
<input id="endpoint" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;" type="text" value="${
|
||||||
|
data.endpoint
|
||||||
}">
|
}">
|
||||||
</label>
|
</label>
|
||||||
<div style="color: white;">
|
<div style="color: white;">
|
||||||
API Key: User / Org <button style="font-size: 18px;">${data.displayName ?? ""
|
API Key: User / Org <button style="font-size: 18px;">${
|
||||||
|
data.displayName ?? ""
|
||||||
}</button>
|
}</button>
|
||||||
<input id="apiKey" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;" type="password" value="${data.apiKey
|
<input id="apiKey" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;" type="password" value="${
|
||||||
|
data.apiKey
|
||||||
}">
|
}">
|
||||||
<button id="loginButton" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;">
|
<button id="loginButton" style="margin-top: 8px; width: 100%; height:40px; box-sizing: border-box; padding: 0px 6px;">
|
||||||
${data.apiKey ? "Re-login with ComfyDeploy" : "Login with ComfyDeploy"
|
${
|
||||||
|
data.apiKey
|
||||||
|
? "Re-login with ComfyDeploy"
|
||||||
|
: "Login with ComfyDeploy"
|
||||||
}
|
}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1138,7 +1272,7 @@ export class ConfigDialog extends ComfyDialog {
|
|||||||
clearInterval(poll);
|
clearInterval(poll);
|
||||||
infoDialog.showMessage(
|
infoDialog.showMessage(
|
||||||
"Timeout",
|
"Timeout",
|
||||||
"Wait too long for the response, please try re-login",
|
"Wait too long for the response, please try re-login"
|
||||||
);
|
);
|
||||||
}, 30000); // Stop polling after 30 seconds
|
}, 30000); // Stop polling after 30 seconds
|
||||||
|
|
||||||
@@ -1149,14 +1283,15 @@ export class ConfigDialog extends ComfyDialog {
|
|||||||
if (json.api_key) {
|
if (json.api_key) {
|
||||||
this.save(json.api_key, json.name);
|
this.save(json.api_key, json.name);
|
||||||
this.close();
|
this.close();
|
||||||
this.container.querySelector("#apiKey").value = json.api_key;
|
this.container.querySelector("#apiKey").value =
|
||||||
|
json.api_key;
|
||||||
// infoDialog.show();
|
// infoDialog.show();
|
||||||
clearInterval(this.poll);
|
clearInterval(this.poll);
|
||||||
clearTimeout(this.timeout);
|
clearTimeout(this.timeout);
|
||||||
// Refresh dialog
|
// Refresh dialog
|
||||||
const a = await confirmDialog.confirm(
|
const a = await confirmDialog.confirm(
|
||||||
"Authenticated",
|
"Authenticated",
|
||||||
`<div>You will be able to upload workflow to <button style="font-size: 18px; width: fit;">${json.name}</button></div>`,
|
`<div>You will be able to upload workflow to <button style="font-size: 18px; width: fit;">${json.name}</button></div>`
|
||||||
);
|
);
|
||||||
configDialog.show();
|
configDialog.show();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,9 @@ const createRunRoute = createRoute({
|
|||||||
export const registerCreateRunRoute = (app: App) => {
|
export const registerCreateRunRoute = (app: App) => {
|
||||||
app.openapi(createRunRoute, async (c) => {
|
app.openapi(createRunRoute, async (c) => {
|
||||||
const data = c.req.valid("json");
|
const data = c.req.valid("json");
|
||||||
const origin = new URL(c.req.url).origin;
|
const proto = c.req.headers.get('x-forwarded-proto') || "http";
|
||||||
|
const host = c.req.headers.get('x-forwarded-host') || c.req.headers.get('host');
|
||||||
|
const origin = `${proto}://${host}` || new URL(c.req.url).origin;
|
||||||
const apiKeyTokenData = c.get("apiKeyTokenData")!;
|
const apiKeyTokenData = c.get("apiKeyTokenData")!;
|
||||||
|
|
||||||
const { deployment_id, inputs } = data;
|
const { deployment_id, inputs } = data;
|
||||||
|
|||||||
Reference in New Issue
Block a user