mirror of
https://github.com/Comfy-Org/ComfyUI-Manager.git
synced 2026-02-08 20:22:34 +08:00
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
commit
186ef9df45
@ -201,7 +201,7 @@ cm_ctx = Ctx()
|
||||
|
||||
|
||||
def install_node(node_name, is_all=False, cnt_msg=''):
|
||||
if '://' in node_name:
|
||||
if core.is_valid_url(node_name):
|
||||
# install via urls
|
||||
res = core.gitclone_install([node_name])
|
||||
if not res:
|
||||
|
||||
@ -3319,6 +3319,17 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "Nodes:Edit Mask"
|
||||
},
|
||||
{
|
||||
"author": "shadowcz007",
|
||||
"title": "comfyui-liveportrait",
|
||||
"id": "liveportrait",
|
||||
"reference": "https://github.com/shadowcz007/comfyui-liveportrait",
|
||||
"files": [
|
||||
"https://github.com/shadowcz007/comfyui-liveportrait"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "The ComfyUI version of [a/LivePortrait](https://github.com/KwaiVGI/LivePortrait)."
|
||||
},
|
||||
{
|
||||
"author": "ostris",
|
||||
"title": "Ostris Nodes ComfyUI",
|
||||
@ -11081,7 +11092,28 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "Content generation with open source models in comfyui via graq api implementation."
|
||||
},
|
||||
|
||||
{
|
||||
"author": "Tritant",
|
||||
"title": "ComfyUI-CreaPrompt",
|
||||
"id": "creaprompt",
|
||||
"reference": "https://github.com/tritant/ComfyUI_CreaPrompt",
|
||||
"files": [
|
||||
"https://github.com/tritant/ComfyUI_CreaPrompt"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Generate random prompts easily."
|
||||
},
|
||||
{
|
||||
"author": "MiddleKD",
|
||||
"title": "ComfyUI-productfix",
|
||||
"id": "productfix",
|
||||
"reference": "https://github.com/MiddleKD/ComfyUI-productfix",
|
||||
"files": [
|
||||
"https://github.com/MiddleKD/ComfyUI-productfix"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "This is a ComfyUI custom node that helps generate images for e-commerce products while maintaining the text, logo, and details of the original product."
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1999,7 +1999,9 @@
|
||||
],
|
||||
"https://github.com/GraftingRayman/ComfyUI_GraftingRayman": [
|
||||
[
|
||||
"GR Background Remover REMBG",
|
||||
"GR Checkered Board",
|
||||
"GR Counter",
|
||||
"GR Flip Tile Random Inverted",
|
||||
"GR Flip Tile Random Red Ring",
|
||||
"GR Image Details Displayer",
|
||||
@ -2389,6 +2391,7 @@
|
||||
],
|
||||
"https://github.com/JayLyu/ComfyUI_BaiKong_Node": [
|
||||
[
|
||||
"BK_ColorLimit",
|
||||
"BK_ColorSelector",
|
||||
"BK_GradientImage",
|
||||
"BK_Img2Color"
|
||||
@ -3016,6 +3019,21 @@
|
||||
"title_aux": "Mosaica"
|
||||
}
|
||||
],
|
||||
"https://github.com/MiddleKD/ComfyUI-productfix": [
|
||||
[
|
||||
"ApplyLatentInjection",
|
||||
"DetailTransferAdd",
|
||||
"DetailTransferLatentAdd",
|
||||
"GetTextMask",
|
||||
"ResetModelPatcherCalculateWeight",
|
||||
"VQDecoder",
|
||||
"VQEncoder",
|
||||
"VQLoader"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-productfix"
|
||||
}
|
||||
],
|
||||
"https://github.com/MilitantHitchhiker/MilitantHitchhiker-SwitchbladePack": [
|
||||
[
|
||||
"IntegratedRandomPromptGenerator",
|
||||
@ -3564,6 +3582,7 @@
|
||||
"LatentInsertWithBBox(FaceParsing)",
|
||||
"LatentSize(FaceParsing)",
|
||||
"MaskComposite(FaceParsing)",
|
||||
"MaskInsertWithBBox(FaceParsing)",
|
||||
"MaskListComposite(FaceParsing)",
|
||||
"MaskListSelect(FaceParsing)",
|
||||
"MaskToBBox(FaceParsing)",
|
||||
@ -9803,6 +9822,8 @@
|
||||
"github_tool",
|
||||
"google_tool",
|
||||
"interpreter_tool",
|
||||
"json_get_value",
|
||||
"json_parser",
|
||||
"keyword_tool",
|
||||
"listen_audio",
|
||||
"llama_guff_loader",
|
||||
@ -9832,6 +9853,7 @@
|
||||
"tool_combine",
|
||||
"tool_combine_plus",
|
||||
"weather_tool",
|
||||
"weekday_tool",
|
||||
"wikipedia_tool",
|
||||
"work_wechat",
|
||||
"work_wechat_tool",
|
||||
@ -11189,6 +11211,32 @@
|
||||
"title_aux": "Marigold depth estimation in ComfyUI"
|
||||
}
|
||||
],
|
||||
"https://github.com/kijai/ComfyUI-MimicMotionWrapper": [
|
||||
[
|
||||
"DiffusersScheduler",
|
||||
"DownloadAndLoadMimicMotionModel",
|
||||
"MimicMotionDecode",
|
||||
"MimicMotionGetPoses",
|
||||
"MimicMotionSampler"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-MimicMotionWrapper"
|
||||
}
|
||||
],
|
||||
"https://github.com/kijai/ComfyUI-OpenDiTWrapper": [
|
||||
[
|
||||
"DownloadAndLoadOpenDiTT5Model",
|
||||
"DownloadAndLoadOpenSoraModel",
|
||||
"DownloadAndLoadOpenSoraVAE",
|
||||
"OpenDiTConditioning",
|
||||
"OpenDiTSampler",
|
||||
"OpenSoraDecode",
|
||||
"OpenSoraEncodeReference"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-OpenDiTWrapper"
|
||||
}
|
||||
],
|
||||
"https://github.com/kijai/ComfyUI-SUPIR": [
|
||||
[
|
||||
"SUPIR_Upscale",
|
||||
@ -11460,7 +11508,9 @@
|
||||
"TclExtractFramesFromVideo",
|
||||
"TclExtractFramesFromVideoFile",
|
||||
"TclFrames2Video",
|
||||
"TclSaveVideoFromFrames"
|
||||
"TclSaveVideoFromFrames",
|
||||
"TclYoloV8Segmentation",
|
||||
"TclYoloV9Segmentation"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-TRA"
|
||||
@ -13021,6 +13071,7 @@
|
||||
"ConditioningMultiplier_PoP",
|
||||
"ConditioningNormalizer_PoP",
|
||||
"DallE3_PoP",
|
||||
"EfficientAttention",
|
||||
"LoadImageResizer_PoP",
|
||||
"LoraStackLoader10_PoP",
|
||||
"LoraStackLoader_PoP",
|
||||
@ -13579,6 +13630,14 @@
|
||||
"title_aux": "comfyui-edit-mask"
|
||||
}
|
||||
],
|
||||
"https://github.com/shadowcz007/comfyui-liveportrait": [
|
||||
[
|
||||
"LivePortraitNode"
|
||||
],
|
||||
{
|
||||
"title_aux": "comfyui-liveportrait"
|
||||
}
|
||||
],
|
||||
"https://github.com/shadowcz007/comfyui-mixlab-nodes": [
|
||||
[
|
||||
"3DImage",
|
||||
@ -14600,6 +14659,14 @@
|
||||
"title_aux": "quadmoon's ComfyUI nodes"
|
||||
}
|
||||
],
|
||||
"https://github.com/tritant/ComfyUI_CreaPrompt": [
|
||||
[
|
||||
"CreaPrompt"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-CreaPrompt"
|
||||
}
|
||||
],
|
||||
"https://github.com/trojblue/trNodes": [
|
||||
[
|
||||
"trColorCorrection",
|
||||
|
||||
2503
github-stats.json
2503
github-stats.json
File diff suppressed because it is too large
Load Diff
@ -23,7 +23,7 @@ sys.path.append(glob_path)
|
||||
import cm_global
|
||||
from manager_util import *
|
||||
|
||||
version = [2, 43]
|
||||
version = [2, 44, 1]
|
||||
version_str = f"V{version[0]}.{version[1]}" + (f'.{version[2]}' if len(version) > 2 else '')
|
||||
|
||||
|
||||
@ -515,10 +515,16 @@ class GitProgress(RemoteProgress):
|
||||
|
||||
def is_valid_url(url):
|
||||
try:
|
||||
# Check for HTTP/HTTPS URL format
|
||||
result = urlparse(url)
|
||||
return all([result.scheme, result.netloc])
|
||||
except ValueError:
|
||||
return False
|
||||
if all([result.scheme, result.netloc]):
|
||||
return True
|
||||
finally:
|
||||
# Check for SSH git URL format
|
||||
pattern = re.compile(r"^(.+@|ssh:\/\/).+:.+$")
|
||||
if pattern.match(url):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def gitclone_install(files, instant_execution=False, msg_prefix=''):
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
import { api } from "../../scripts/api.js";
|
||||
import { app } from "../../scripts/app.js";
|
||||
import { api } from "../../scripts/api.js"
|
||||
import { ComfyDialog, $el } from "../../scripts/ui.js";
|
||||
import { $el, ComfyDialog } from "../../scripts/ui.js";
|
||||
import {
|
||||
ShareDialog,
|
||||
SUPPORTED_OUTPUT_NODE_TYPES,
|
||||
getPotentialOutputsAndOutputNodes,
|
||||
ShareDialog,
|
||||
ShareDialogChooser,
|
||||
getPotentialOutputsAndOutputNodes,
|
||||
showOpenArtShareDialog,
|
||||
showShareDialog,
|
||||
showYouMLShareDialog
|
||||
} from "./comfyui-share-common.js";
|
||||
import { OpenArtShareDialog } from "./comfyui-share-openart.js";
|
||||
import { free_models, install_pip, install_via_git_url, manager_instance, rebootAPI, setManagerInstance, show_message } from "./common.js";
|
||||
import { ComponentBuilderDialog, getPureName, load_components, set_component_policy } from "./components-manager.js";
|
||||
import { CustomNodesManager } from "./custom-nodes-manager.js";
|
||||
import { ModelManager } from "./model-manager.js";
|
||||
import { SnapshotManager } from "./snapshot.js";
|
||||
import { manager_instance, setManagerInstance, install_via_git_url, install_pip, rebootAPI, free_models, show_message } from "./common.js";
|
||||
import { ComponentBuilderDialog, load_components, set_component_policy, getPureName } from "./components-manager.js";
|
||||
import { set_double_click_policy } from "./node_fixer.js";
|
||||
import { SnapshotManager } from "./snapshot.js";
|
||||
|
||||
var docStyle = document.createElement('style');
|
||||
docStyle.innerHTML = `
|
||||
@ -897,6 +897,7 @@ class ManagerMenuDialog extends ComfyDialog {
|
||||
['youml', 'YouML'],
|
||||
['matrix', 'Matrix Server'],
|
||||
['comfyworkflows', 'ComfyWorkflows'],
|
||||
['copus', 'Copus'],
|
||||
['all', 'All'],
|
||||
];
|
||||
for (const option of share_options) {
|
||||
@ -1234,6 +1235,15 @@ class ManagerMenuDialog extends ComfyDialog {
|
||||
modifyButtonStyle(url);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Open 'Copus.io'",
|
||||
callback: () => {
|
||||
const url = "https://www.copus.io";
|
||||
localStorage.setItem("wg_last_visited", url);
|
||||
window.open(url, url);
|
||||
modifyButtonStyle(url);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Close",
|
||||
callback: () => {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { app } from "../../scripts/app.js";
|
||||
import { api } from "../../scripts/api.js";
|
||||
import { ComfyDialog, $el } from "../../scripts/ui.js";
|
||||
import { app } from "../../scripts/app.js";
|
||||
import { $el, ComfyDialog } from "../../scripts/ui.js";
|
||||
import { CopusShareDialog } from "./comfyui-share-copus.js";
|
||||
import { OpenArtShareDialog } from "./comfyui-share-openart.js";
|
||||
import { YouMLShareDialog } from "./comfyui-share-youml.js";
|
||||
|
||||
@ -187,6 +188,21 @@ export const shareToEsheep= () => {
|
||||
})
|
||||
}
|
||||
|
||||
export const showCopusShareDialog = () => {
|
||||
if (!CopusShareDialog.instance) {
|
||||
CopusShareDialog.instance = new CopusShareDialog();
|
||||
}
|
||||
|
||||
return app.graphToPrompt()
|
||||
.then(prompt => {
|
||||
return app.graph._nodes;
|
||||
})
|
||||
.then(nodes => {
|
||||
const { potential_outputs, potential_output_nodes } = getPotentialOutputsAndOutputNodes(nodes);
|
||||
CopusShareDialog.instance.show({ potential_outputs, potential_output_nodes});
|
||||
})
|
||||
}
|
||||
|
||||
export const showOpenArtShareDialog = () => {
|
||||
if (!OpenArtShareDialog.instance) {
|
||||
OpenArtShareDialog.instance = new OpenArtShareDialog();
|
||||
@ -316,6 +332,16 @@ export class ShareDialogChooser extends ComfyDialog {
|
||||
this.close();
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "Copus",
|
||||
textContent: "Copus",
|
||||
website: "https://www.copus.io",
|
||||
description: "🔴 Permanently store and secure ownership of your workflow on the open-source platform: <a style='color:white;' href='https://copus.io' target='_blank'>Copus.io</a>",
|
||||
onclick: () => {
|
||||
showCopusShareDialog();
|
||||
this.close();
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
function createShareButtonsWithDescriptions() {
|
||||
|
||||
892
js/comfyui-share-copus.js
Normal file
892
js/comfyui-share-copus.js
Normal file
@ -0,0 +1,892 @@
|
||||
import { app } from "../../scripts/app.js";
|
||||
import { $el, ComfyDialog } from "../../scripts/ui.js";
|
||||
const env = "prod";
|
||||
|
||||
let DEFAULT_HOMEPAGE_URL = "https://copus.io";
|
||||
|
||||
let API_ENDPOINT = "https://api.client.prod.copus.io/copus-client";
|
||||
|
||||
if (env !== "prod") {
|
||||
API_ENDPOINT = "https://api.dev.copus.io/copus-client";
|
||||
DEFAULT_HOMEPAGE_URL = "https://test.copus.io";
|
||||
}
|
||||
|
||||
const style = `
|
||||
.copus-share-dialog a {
|
||||
color: #f8f8f8;
|
||||
}
|
||||
.copus-share-dialog a:hover {
|
||||
color: #007bff;
|
||||
}
|
||||
.output_label {
|
||||
border: 5px solid transparent;
|
||||
}
|
||||
.output_label:hover {
|
||||
border: 5px solid #59E8C6;
|
||||
}
|
||||
.output_label.checked {
|
||||
border: 5px solid #59E8C6;
|
||||
}
|
||||
`;
|
||||
|
||||
// Shared component styles
|
||||
const sectionStyle = {
|
||||
marginBottom: 0,
|
||||
padding: 0,
|
||||
borderRadius: "8px",
|
||||
boxShadow: "0 2px 4px rgba(0, 0, 0, 0.05)",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
position: "relative",
|
||||
};
|
||||
|
||||
export class CopusShareDialog extends ComfyDialog {
|
||||
static instance = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
$el("style", {
|
||||
textContent: style,
|
||||
parent: document.head,
|
||||
});
|
||||
this.element = $el(
|
||||
"div.comfy-modal.copus-share-dialog",
|
||||
{
|
||||
parent: document.body,
|
||||
style: {
|
||||
"overflow-y": "auto",
|
||||
},
|
||||
},
|
||||
[$el("div.comfy-modal-content", {}, [...this.createButtons()])]
|
||||
);
|
||||
this.selectedOutputIndex = 0;
|
||||
this.selectedNodeId = null;
|
||||
this.uploadedImages = [];
|
||||
this.allFilesImages = [];
|
||||
this.selectedFile = null;
|
||||
this.allFiles = [];
|
||||
this.titleNum = 0;
|
||||
}
|
||||
|
||||
createButtons() {
|
||||
const inputStyle = {
|
||||
display: "block",
|
||||
minWidth: "500px",
|
||||
width: "100%",
|
||||
padding: "10px",
|
||||
margin: "10px 0",
|
||||
borderRadius: "4px",
|
||||
border: "1px solid #ddd",
|
||||
boxSizing: "border-box",
|
||||
};
|
||||
|
||||
const textAreaStyle = {
|
||||
display: "block",
|
||||
minWidth: "500px",
|
||||
width: "100%",
|
||||
padding: "10px",
|
||||
margin: "10px 0",
|
||||
borderRadius: "4px",
|
||||
border: "1px solid #ddd",
|
||||
boxSizing: "border-box",
|
||||
minHeight: "100px",
|
||||
background: "#222",
|
||||
resize: "vertical",
|
||||
color: "#f2f2f2",
|
||||
fontFamily: "Arial",
|
||||
fontWeight: "400",
|
||||
fontSize: "15px",
|
||||
};
|
||||
|
||||
const hyperLinkStyle = {
|
||||
display: "block",
|
||||
marginBottom: "15px",
|
||||
fontWeight: "bold",
|
||||
fontSize: "14px",
|
||||
};
|
||||
|
||||
const labelStyle = {
|
||||
color: "#f8f8f8",
|
||||
display: "block",
|
||||
margin: "10px 0 0 0",
|
||||
fontWeight: "bold",
|
||||
textDecoration: "none",
|
||||
};
|
||||
|
||||
const buttonStyle = {
|
||||
padding: "10px 80px",
|
||||
margin: "10px 5px",
|
||||
borderRadius: "4px",
|
||||
border: "none",
|
||||
cursor: "pointer",
|
||||
color: "#fff",
|
||||
backgroundColor: "#007bff",
|
||||
};
|
||||
|
||||
// upload images input
|
||||
this.uploadImagesInput = $el("input", {
|
||||
type: "file",
|
||||
multiple: false,
|
||||
style: inputStyle,
|
||||
accept: "image/*",
|
||||
});
|
||||
|
||||
this.uploadImagesInput.addEventListener("change", async (e) => {
|
||||
const file = e.target.files[0];
|
||||
if (!file) {
|
||||
this.previewImage.src = "";
|
||||
this.previewImage.style.display = "none";
|
||||
return;
|
||||
}
|
||||
const reader = new FileReader();
|
||||
reader.onload = async (e) => {
|
||||
const imgData = e.target.result;
|
||||
this.previewImage.src = imgData;
|
||||
this.previewImage.style.display = "block";
|
||||
this.selectedFile = null;
|
||||
// Once user uploads an image, we uncheck all radio buttons
|
||||
this.radioButtons.forEach((ele) => {
|
||||
ele.checked = false;
|
||||
ele.parentElement.classList.remove("checked");
|
||||
});
|
||||
|
||||
// Add the opacity style toggle here to indicate that they only need
|
||||
// to upload one image or choose one from the outputs.
|
||||
this.outputsSection.style.opacity = 0.35;
|
||||
this.uploadImagesInput.style.opacity = 1;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
// preview image
|
||||
this.previewImage = $el("img", {
|
||||
src: "",
|
||||
style: {
|
||||
width: "100%",
|
||||
maxHeight: "100px",
|
||||
objectFit: "contain",
|
||||
display: "none",
|
||||
marginTop: "10px",
|
||||
},
|
||||
});
|
||||
|
||||
this.keyInput = $el("input", {
|
||||
type: "password",
|
||||
placeholder: "Copy & paste your API key",
|
||||
style: inputStyle,
|
||||
});
|
||||
this.TitleInput = $el("input", {
|
||||
type: "text",
|
||||
placeholder: "Title (Required)",
|
||||
style: inputStyle,
|
||||
maxLength: "70",
|
||||
oninput: () => {
|
||||
const titleNum = this.TitleInput.value.length;
|
||||
titleNumDom.textContent = `${titleNum}/70`;
|
||||
},
|
||||
});
|
||||
this.SubTitleInput = $el("input", {
|
||||
type: "text",
|
||||
placeholder: "Subtitle (Optional)",
|
||||
style: inputStyle,
|
||||
maxLength: "70",
|
||||
oninput: () => {
|
||||
const titleNum = this.SubTitleInput.value.length;
|
||||
subTitleNumDom.textContent = `${titleNum}/70`;
|
||||
},
|
||||
});
|
||||
this.descriptionInput = $el("textarea", {
|
||||
placeholder: "Content (Optional)",
|
||||
style: {
|
||||
...textAreaStyle,
|
||||
minHeight: "100px",
|
||||
},
|
||||
});
|
||||
|
||||
// Header Section
|
||||
const headerSection = $el("h3", {
|
||||
textContent: "Share your workflow to Copus",
|
||||
size: 3,
|
||||
color: "white",
|
||||
style: {
|
||||
"text-align": "center",
|
||||
color: "white",
|
||||
margin: "0 0 10px 0",
|
||||
},
|
||||
});
|
||||
this.getAPIKeyLink = $el(
|
||||
"a",
|
||||
{
|
||||
style: {
|
||||
...hyperLinkStyle,
|
||||
color: "#59E8C6",
|
||||
},
|
||||
href: `${DEFAULT_HOMEPAGE_URL}?fromPage=comfyUI`,
|
||||
target: "_blank",
|
||||
},
|
||||
["👉 Get your API key here"]
|
||||
);
|
||||
const linkSection = $el(
|
||||
"div",
|
||||
{
|
||||
style: {
|
||||
marginTop: "10px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
},
|
||||
},
|
||||
[
|
||||
// this.communityLink,
|
||||
this.getAPIKeyLink,
|
||||
]
|
||||
);
|
||||
|
||||
// Account Section
|
||||
const accountSection = $el("div", { style: sectionStyle }, [
|
||||
$el("label", { style: labelStyle }, ["1️⃣ Copus API Key"]),
|
||||
this.keyInput,
|
||||
]);
|
||||
|
||||
// Output Upload Section
|
||||
const outputUploadSection = $el("div", { style: sectionStyle }, [
|
||||
$el(
|
||||
"label",
|
||||
{
|
||||
style: {
|
||||
...labelStyle,
|
||||
margin: "10px 0 0 0",
|
||||
},
|
||||
},
|
||||
["2️⃣ Image/Thumbnail (Required)"]
|
||||
),
|
||||
this.previewImage,
|
||||
this.uploadImagesInput,
|
||||
]);
|
||||
|
||||
// Outputs Section
|
||||
this.outputsSection = $el(
|
||||
"div",
|
||||
{
|
||||
id: "selectOutputs",
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const titleNumDom = $el(
|
||||
"label",
|
||||
{
|
||||
style: {
|
||||
fontSize: "12px",
|
||||
position: "absolute",
|
||||
right: "10px",
|
||||
bottom: "-10px",
|
||||
color: "#999",
|
||||
},
|
||||
},
|
||||
["0/70"]
|
||||
);
|
||||
const subTitleNumDom = $el(
|
||||
"label",
|
||||
{
|
||||
style: {
|
||||
fontSize: "12px",
|
||||
position: "absolute",
|
||||
right: "10px",
|
||||
bottom: "-10px",
|
||||
color: "#999",
|
||||
},
|
||||
},
|
||||
["0/70"]
|
||||
);
|
||||
const descriptionNumDom = $el(
|
||||
"label",
|
||||
{
|
||||
style: {
|
||||
fontSize: "12px",
|
||||
position: "absolute",
|
||||
right: "10px",
|
||||
bottom: "-10px",
|
||||
color: "#999",
|
||||
},
|
||||
},
|
||||
["0/70"]
|
||||
);
|
||||
// Additional Inputs Section
|
||||
const additionalInputsSection = $el(
|
||||
"div",
|
||||
{ style: { ...sectionStyle, } },
|
||||
[
|
||||
$el("label", { style: labelStyle }, ["3️⃣ Title "]),
|
||||
this.TitleInput,
|
||||
titleNumDom,
|
||||
]
|
||||
);
|
||||
const SubtitleSection = $el("div", { style: sectionStyle }, [
|
||||
$el("label", { style: labelStyle }, ["4️⃣ Subtitle "]),
|
||||
this.SubTitleInput,
|
||||
subTitleNumDom,
|
||||
]);
|
||||
const DescriptionSection = $el("div", { style: sectionStyle }, [
|
||||
$el("label", { style: labelStyle }, ["5️⃣ Description "]),
|
||||
this.descriptionInput,
|
||||
// descriptionNumDom,
|
||||
]);
|
||||
// switch between outputs section and additional inputs section
|
||||
this.radioButtons = [];
|
||||
|
||||
this.radioButtonsCheck = $el("input", {
|
||||
type: "radio",
|
||||
name: "output_type",
|
||||
value: "0",
|
||||
id: "blockchain1",
|
||||
checked: true,
|
||||
});
|
||||
this.radioButtonsCheckOff = $el("input", {
|
||||
type: "radio",
|
||||
name: "output_type",
|
||||
value: "1",
|
||||
id: "blockchain",
|
||||
});
|
||||
|
||||
const blockChainSection = $el("div", { style: sectionStyle }, [
|
||||
$el("label", { style: labelStyle }, ["6️⃣ Store on blockchain "]),
|
||||
$el(
|
||||
"label",
|
||||
{
|
||||
style: {
|
||||
marginTop: "10px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
cursor: "pointer",
|
||||
},
|
||||
},
|
||||
[
|
||||
this.radioButtonsCheck,
|
||||
$el("span", { style: { marginLeft: "5px" } }, ["ON"]),
|
||||
]
|
||||
),
|
||||
$el(
|
||||
"label",
|
||||
{ style: { display: "flex", alignItems: "center", cursor: "pointer" } },
|
||||
[
|
||||
this.radioButtonsCheckOff,
|
||||
$el("span", { style: { marginLeft: "5px" } }, ["OFF"]),
|
||||
]
|
||||
),
|
||||
$el(
|
||||
"p",
|
||||
{ style: { fontSize: "16px", color: "#fff", margin: "10px 0 0 0" } },
|
||||
["Secure ownership with a permanent & decentralized storage"]
|
||||
),
|
||||
]);
|
||||
// Message Section
|
||||
this.message = $el(
|
||||
"div",
|
||||
{
|
||||
style: {
|
||||
color: "#ff3d00",
|
||||
textAlign: "center",
|
||||
padding: "10px",
|
||||
fontSize: "20px",
|
||||
},
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
this.shareButton = $el("button", {
|
||||
type: "submit",
|
||||
textContent: "Share",
|
||||
style: buttonStyle,
|
||||
onclick: () => {
|
||||
this.handleShareButtonClick();
|
||||
},
|
||||
});
|
||||
|
||||
// Share and Close Buttons
|
||||
const buttonsSection = $el(
|
||||
"div",
|
||||
{
|
||||
style: {
|
||||
textAlign: "right",
|
||||
marginTop: "20px",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
},
|
||||
[
|
||||
$el("button", {
|
||||
type: "button",
|
||||
textContent: "Close",
|
||||
style: {
|
||||
...buttonStyle,
|
||||
backgroundColor: undefined,
|
||||
},
|
||||
onclick: () => {
|
||||
this.close();
|
||||
},
|
||||
}),
|
||||
this.shareButton,
|
||||
]
|
||||
);
|
||||
|
||||
// Composing the full layout
|
||||
const layout = [
|
||||
headerSection,
|
||||
linkSection,
|
||||
accountSection,
|
||||
outputUploadSection,
|
||||
this.outputsSection,
|
||||
additionalInputsSection,
|
||||
SubtitleSection,
|
||||
DescriptionSection,
|
||||
// contestSection,
|
||||
blockChainSection,
|
||||
this.message,
|
||||
buttonsSection,
|
||||
];
|
||||
|
||||
return layout;
|
||||
}
|
||||
/**
|
||||
* api
|
||||
* @param {url} path
|
||||
* @param {params} options
|
||||
* @param {statusText} statusText
|
||||
* @returns
|
||||
*/
|
||||
async fetchApi(path, options, statusText) {
|
||||
if (statusText) {
|
||||
this.message.textContent = statusText;
|
||||
}
|
||||
const fullPath = new URL(API_ENDPOINT + path);
|
||||
const response = await fetch(fullPath, options);
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
if (statusText) {
|
||||
this.message.textContent = "";
|
||||
}
|
||||
const data = await response.json();
|
||||
return {
|
||||
ok: response.ok,
|
||||
statusText: response.statusText,
|
||||
status: response.status,
|
||||
data,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @param {file} uploadFile
|
||||
*/
|
||||
async uploadThumbnail(uploadFile, type) {
|
||||
const form = new FormData();
|
||||
form.append("file", uploadFile);
|
||||
form.append("apiToken", this.keyInput.value);
|
||||
try {
|
||||
const res = await this.fetchApi(
|
||||
`/client/common/opus/uploadImage`,
|
||||
{
|
||||
method: "POST",
|
||||
body: form,
|
||||
},
|
||||
"Uploading thumbnail..."
|
||||
);
|
||||
if (res.status && res.data.status && res.data) {
|
||||
const { data } = res.data;
|
||||
if (type) {
|
||||
this.allFilesImages.push({
|
||||
url: data,
|
||||
});
|
||||
}
|
||||
this.uploadedImages.push({
|
||||
url: data,
|
||||
});
|
||||
} else {
|
||||
throw new Error("make sure your API key is correct and try again later");
|
||||
}
|
||||
} catch (e) {
|
||||
if (e?.response?.status === 413) {
|
||||
throw new Error("File size is too large (max 20MB)");
|
||||
} else {
|
||||
throw new Error("Error uploading thumbnail: " + e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async handleShareButtonClick() {
|
||||
this.message.textContent = "";
|
||||
try {
|
||||
this.shareButton.disabled = true;
|
||||
this.shareButton.textContent = "Sharing...";
|
||||
await this.share();
|
||||
} catch (e) {
|
||||
alert(e.message);
|
||||
}
|
||||
this.shareButton.disabled = false;
|
||||
this.shareButton.textContent = "Share";
|
||||
}
|
||||
/**
|
||||
* share
|
||||
* @param {string} title
|
||||
* @param {string} subtitle
|
||||
* @param {string} content
|
||||
* @param {boolean} storeOnChain
|
||||
* @param {string} coverUrl
|
||||
* @param {string[]} imageUrls
|
||||
* @param {string} apiToken
|
||||
*/
|
||||
async share() {
|
||||
const prompt = await app.graphToPrompt();
|
||||
const workflowJSON = prompt["workflow"];
|
||||
const form_values = {
|
||||
title: this.TitleInput.value,
|
||||
subTitle: this.SubTitleInput.value,
|
||||
content: this.descriptionInput.value,
|
||||
storeOnChain: this.radioButtonsCheck.checked ? true : false,
|
||||
};
|
||||
|
||||
if (!this.keyInput.value) {
|
||||
throw new Error("API key is required");
|
||||
}
|
||||
|
||||
if (!this.uploadImagesInput.files[0] && !this.selectedFile) {
|
||||
throw new Error("Thumbnail is required");
|
||||
}
|
||||
|
||||
if (!form_values.title) {
|
||||
throw new Error("Title is required");
|
||||
}
|
||||
|
||||
if (!this.uploadedImages.length) {
|
||||
if (this.selectedFile) {
|
||||
await this.uploadThumbnail(this.selectedFile);
|
||||
} else {
|
||||
for (const file of this.uploadImagesInput.files) {
|
||||
try {
|
||||
await this.uploadThumbnail(file);
|
||||
} catch (e) {
|
||||
this.uploadedImages = [];
|
||||
throw new Error(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.uploadImagesInput.files.length === 0) {
|
||||
throw new Error("No thumbnail uploaded");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.allFiles.length > 0) {
|
||||
for (const file of this.allFiles) {
|
||||
try {
|
||||
await this.uploadThumbnail(file, true);
|
||||
} catch (e) {
|
||||
this.allFilesImages = [];
|
||||
throw new Error(e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
const res = await this.fetchApi(
|
||||
"/client/common/opus/shareFromComfyUI",
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
workflowJson: workflowJSON,
|
||||
apiToken: this.keyInput.value,
|
||||
coverUrl: this.uploadedImages[0].url,
|
||||
imageUrls: this.allFilesImages.map((image) => image.url),
|
||||
...form_values,
|
||||
}),
|
||||
},
|
||||
"Uploading workflow..."
|
||||
);
|
||||
|
||||
if (res.status && res.data.status && res.data) {
|
||||
localStorage.setItem("copus_token",this.keyInput.value);
|
||||
const { data } = res.data;
|
||||
if (data) {
|
||||
const url = `${DEFAULT_HOMEPAGE_URL}/work/${data}`;
|
||||
this.message.innerHTML = `Workflow has been shared successfully. <a href="${url}" target="_blank">Click here to view it.</a>`;
|
||||
this.previewImage.src = "";
|
||||
this.previewImage.style.display = "none";
|
||||
this.uploadedImages = [];
|
||||
this.allFilesImages = [];
|
||||
this.allFiles = [];
|
||||
this.TitleInput.value = "";
|
||||
this.SubTitleInput.value = "";
|
||||
this.descriptionInput.value = "";
|
||||
this.selectedFile = null;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error("Error sharing workflow: " + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
async fetchImageBlob(url) {
|
||||
const response = await fetch(url);
|
||||
const blob = await response.blob();
|
||||
return blob;
|
||||
}
|
||||
|
||||
async show({ potential_outputs, potential_output_nodes } = {}) {
|
||||
// Sort `potential_output_nodes` by node ID to make the order always
|
||||
// consistent, but we should also keep `potential_outputs` in the same
|
||||
// order as `potential_output_nodes`.
|
||||
const potential_output_to_order = {};
|
||||
potential_output_nodes.forEach((node, index) => {
|
||||
if (node.id in potential_output_to_order) {
|
||||
potential_output_to_order[node.id][1].push(potential_outputs[index]);
|
||||
} else {
|
||||
potential_output_to_order[node.id] = [node, [potential_outputs[index]]];
|
||||
}
|
||||
});
|
||||
// Sort the object `potential_output_to_order` by key (node ID)
|
||||
const sorted_potential_output_to_order = Object.fromEntries(
|
||||
Object.entries(potential_output_to_order).sort(
|
||||
(a, b) => a[0].id - b[0].id
|
||||
)
|
||||
);
|
||||
const sorted_potential_outputs = [];
|
||||
const sorted_potential_output_nodes = [];
|
||||
for (const [key, value] of Object.entries(
|
||||
sorted_potential_output_to_order
|
||||
)) {
|
||||
sorted_potential_output_nodes.push(value[0]);
|
||||
sorted_potential_outputs.push(...value[1]);
|
||||
}
|
||||
potential_output_nodes = sorted_potential_output_nodes;
|
||||
potential_outputs = sorted_potential_outputs;
|
||||
const apiToken = localStorage.getItem("copus_token");
|
||||
this.message.innerHTML = "";
|
||||
this.message.textContent = "";
|
||||
this.element.style.display = "block";
|
||||
this.previewImage.src = "";
|
||||
this.previewImage.style.display = "none";
|
||||
this.keyInput.value = apiToken!=null?apiToken:"";
|
||||
this.uploadedImages = [];
|
||||
this.allFilesImages = [];
|
||||
this.allFiles = [];
|
||||
// If `selectedNodeId` is provided, we will select the corresponding radio
|
||||
// button for the node. In addition, we move the selected radio button to
|
||||
// the top of the list.
|
||||
if (this.selectedNodeId) {
|
||||
const index = potential_output_nodes.findIndex(
|
||||
(node) => node.id === this.selectedNodeId
|
||||
);
|
||||
if (index >= 0) {
|
||||
this.selectedOutputIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
this.radioButtons = [];
|
||||
const new_radio_buttons = $el(
|
||||
"div",
|
||||
{
|
||||
id: "selectOutput-Options",
|
||||
style: {
|
||||
"overflow-y": "scroll",
|
||||
"max-height": "200px",
|
||||
display: "grid",
|
||||
"grid-template-columns": "repeat(auto-fit, minmax(100px, 1fr))",
|
||||
"grid-template-rows": "auto",
|
||||
"grid-column-gap": "10px",
|
||||
"grid-row-gap": "10px",
|
||||
"margin-bottom": "10px",
|
||||
padding: "10px",
|
||||
"border-radius": "8px",
|
||||
"box-shadow": "0 2px 4px rgba(0, 0, 0, 0.05)",
|
||||
"background-color": "var(--bg-color)",
|
||||
},
|
||||
},
|
||||
potential_outputs.map((output, index) => {
|
||||
const { node_id } = output;
|
||||
const radio_button = $el(
|
||||
"input",
|
||||
{
|
||||
type: "radio",
|
||||
name: "selectOutputImages",
|
||||
value: index,
|
||||
required: index === 0,
|
||||
},
|
||||
[]
|
||||
);
|
||||
let radio_button_img;
|
||||
let filename;
|
||||
if (output.type === "image" || output.type === "temp") {
|
||||
radio_button_img = $el(
|
||||
"img",
|
||||
{
|
||||
src: `/view?filename=${output.image.filename}&subfolder=${output.image.subfolder}&type=${output.image.type}`,
|
||||
style: {
|
||||
width: "100px",
|
||||
height: "100px",
|
||||
objectFit: "cover",
|
||||
borderRadius: "5px",
|
||||
},
|
||||
},
|
||||
[]
|
||||
);
|
||||
filename = output.image.filename;
|
||||
} else if (output.type === "output") {
|
||||
radio_button_img = $el(
|
||||
"img",
|
||||
{
|
||||
src: output.output.value,
|
||||
style: {
|
||||
width: "auto",
|
||||
height: "100px",
|
||||
objectFit: "cover",
|
||||
borderRadius: "5px",
|
||||
},
|
||||
},
|
||||
[]
|
||||
);
|
||||
filename = output.filename;
|
||||
} else {
|
||||
// unsupported output type
|
||||
// this should never happen
|
||||
radio_button_img = $el(
|
||||
"img",
|
||||
{
|
||||
src: "",
|
||||
style: { width: "auto", height: "100px" },
|
||||
},
|
||||
[]
|
||||
);
|
||||
}
|
||||
const radio_button_text = $el(
|
||||
"span",
|
||||
{
|
||||
style: {
|
||||
color: "gray",
|
||||
display: "block",
|
||||
fontSize: "12px",
|
||||
overflowX: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
textWrap: "nowrap",
|
||||
maxWidth: "100px",
|
||||
},
|
||||
},
|
||||
[output.title]
|
||||
);
|
||||
const node_id_chip = $el(
|
||||
"span",
|
||||
{
|
||||
style: {
|
||||
color: "#FBFBFD",
|
||||
display: "block",
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
fontSize: "12px",
|
||||
overflowX: "hidden",
|
||||
padding: "2px 3px",
|
||||
textOverflow: "ellipsis",
|
||||
textWrap: "nowrap",
|
||||
maxWidth: "100px",
|
||||
position: "absolute",
|
||||
top: "3px",
|
||||
left: "3px",
|
||||
borderRadius: "3px",
|
||||
},
|
||||
},
|
||||
[`Node: ${node_id}`]
|
||||
);
|
||||
radio_button.style.color = "var(--fg-color)";
|
||||
radio_button.checked = this.selectedOutputIndex === index;
|
||||
|
||||
radio_button.onchange = async () => {
|
||||
this.selectedOutputIndex = parseInt(radio_button.value);
|
||||
|
||||
// Remove the "checked" class from all radio buttons
|
||||
this.radioButtons.forEach((ele) => {
|
||||
ele.parentElement.classList.remove("checked");
|
||||
});
|
||||
radio_button.parentElement.classList.add("checked");
|
||||
|
||||
this.fetchImageBlob(radio_button_img.src).then((blob) => {
|
||||
const file = new File([blob], filename, {
|
||||
type: blob.type,
|
||||
});
|
||||
this.previewImage.src = radio_button_img.src;
|
||||
this.previewImage.style.display = "block";
|
||||
this.selectedFile = file;
|
||||
});
|
||||
|
||||
// Add the opacity style toggle here to indicate that they only need
|
||||
// to upload one image or choose one from the outputs.
|
||||
this.outputsSection.style.opacity = 1;
|
||||
this.uploadImagesInput.style.opacity = 0.35;
|
||||
};
|
||||
|
||||
if (radio_button.checked) {
|
||||
this.fetchImageBlob(radio_button_img.src).then((blob) => {
|
||||
const file = new File([blob], filename, {
|
||||
type: blob.type,
|
||||
});
|
||||
this.previewImage.src = radio_button_img.src;
|
||||
this.previewImage.style.display = "block";
|
||||
this.selectedFile = file;
|
||||
});
|
||||
// Add the opacity style toggle here to indicate that they only need
|
||||
// to upload one image or choose one from the outputs.
|
||||
this.outputsSection.style.opacity = 1;
|
||||
this.uploadImagesInput.style.opacity = 0.35;
|
||||
}
|
||||
this.radioButtons.push(radio_button);
|
||||
let src = "";
|
||||
if (output.type === "image" || output.type === "temp") {
|
||||
filename = output.image.filename;
|
||||
src = `/view?filename=${output.image.filename}&subfolder=${output.image.subfolder}&type=${output.image.type}`;
|
||||
} else if (output.type === "output") {
|
||||
src = output.output.value;
|
||||
filename = output.filename;
|
||||
}
|
||||
if (src) {
|
||||
this.fetchImageBlob(src).then((blob) => {
|
||||
const file = new File([blob], filename, {
|
||||
type: blob.type,
|
||||
});
|
||||
this.allFiles.push(file);
|
||||
});
|
||||
}
|
||||
return $el(
|
||||
`label.output_label${radio_button.checked ? ".checked" : ""}`,
|
||||
{
|
||||
style: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
marginBottom: "10px",
|
||||
cursor: "pointer",
|
||||
position: "relative",
|
||||
},
|
||||
},
|
||||
[radio_button_img, radio_button_text, radio_button, node_id_chip]
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
const header = $el(
|
||||
"p",
|
||||
{
|
||||
textContent:
|
||||
this.radioButtons.length === 0
|
||||
? "Queue Prompt to see the outputs"
|
||||
: "Or choose one from the outputs (scroll to see all)",
|
||||
size: 2,
|
||||
color: "white",
|
||||
style: {
|
||||
color: "white",
|
||||
margin: "0 0 5px 0",
|
||||
fontSize: "12px",
|
||||
},
|
||||
},
|
||||
[]
|
||||
);
|
||||
this.outputsSection.innerHTML = "";
|
||||
this.outputsSection.appendChild(header);
|
||||
this.outputsSection.appendChild(new_radio_buttons);
|
||||
}
|
||||
}
|
||||
@ -34,8 +34,9 @@ function isValidURL(url) {
|
||||
if(url.includes('&'))
|
||||
return false;
|
||||
|
||||
const pattern = /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/;
|
||||
return pattern.test(url);
|
||||
const http_pattern = /^(https?|ftp):\/\/[^\s$?#]+$/;
|
||||
const ssh_pattern = /^(.+@|ssh:\/\/).+:.+$/;
|
||||
return http_pattern.test(url) || ssh_pattern.test(url);
|
||||
}
|
||||
|
||||
export async function install_pip(packages) {
|
||||
|
||||
@ -10,17 +10,6 @@
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"author": "kijai",
|
||||
"title": "MimicMotion wrapper for ComfyUI [WIP]",
|
||||
"id": "mimicmotion-wrapper",
|
||||
"reference": "https://github.com/kijai/ComfyUI-MimicMotionWrapper",
|
||||
"files": [
|
||||
"https://github.com/kijai/ComfyUI-MimicMotionWrapper"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Original repo: [a/https://github.com/tencent/MimicMotion](https://github.com/tencent/MimicMotion)"
|
||||
},
|
||||
{
|
||||
"author": "thderoo",
|
||||
"title": "_topfun_s_nodes",
|
||||
@ -41,17 +30,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "This repository provides developers with a way to better manage their ComfyUI model memory. It includes nodes that allow developers to either unload all models or unload one model at a time. These nodes are designed as pass-through nodes, so they can be used anywhere in the flow. The nodes can be found in the 'Unload Model' section.[w/These are massive hammers, and it could be possible to break things, please don't use them if you need finesse.]"
|
||||
},
|
||||
{
|
||||
"author": "kijai",
|
||||
"title": "ComfyUI-OpenDiTWrapper [WIP]",
|
||||
"id": "open-dit-wrapper",
|
||||
"reference": "https://github.com/kijai/ComfyUI-OpenDiTWrapper",
|
||||
"files": [
|
||||
"https://github.com/kijai/ComfyUI-OpenDiTWrapper"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Original repo: [a/https://github.com/NUS-HPC-AI-Lab/OpenDiT](https://github.com/NUS-HPC-AI-Lab/OpenDiT)"
|
||||
},
|
||||
{
|
||||
"author": "GeekyGhost",
|
||||
"title": "ComfyUI-GeekyRemB v2",
|
||||
|
||||
@ -13,6 +13,61 @@
|
||||
|
||||
|
||||
|
||||
{
|
||||
"author": "shadowcz007",
|
||||
"title": "comfyui-liveportrait",
|
||||
"id": "liveportrait",
|
||||
"reference": "https://github.com/shadowcz007/comfyui-liveportrait",
|
||||
"files": [
|
||||
"https://github.com/shadowcz007/comfyui-liveportrait"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "The ComfyUI version of [a/LivePortrait](https://github.com/KwaiVGI/LivePortrait)."
|
||||
},
|
||||
{
|
||||
"author": "MiddleKD",
|
||||
"title": "ComfyUI-productfix",
|
||||
"id": "productfix",
|
||||
"reference": "https://github.com/MiddleKD/ComfyUI-productfix",
|
||||
"files": [
|
||||
"https://github.com/MiddleKD/ComfyUI-productfix"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "This is a ComfyUI custom node that helps generate images for e-commerce products while maintaining the text, logo, and details of the original product."
|
||||
},
|
||||
{
|
||||
"author": "Tritant",
|
||||
"title": "ComfyUI-CreaPrompt",
|
||||
"id": "creaprompt",
|
||||
"reference": "https://github.com/tritant/ComfyUI_CreaPrompt",
|
||||
"files": [
|
||||
"https://github.com/tritant/ComfyUI_CreaPrompt"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Generate random prompts easily."
|
||||
},
|
||||
{
|
||||
"author": "kijai",
|
||||
"title": "ComfyUI-MimicMotionWrapper",
|
||||
"id": "mimicmotion-kijai",
|
||||
"reference": "https://github.com/kijai/ComfyUI-MimicMotionWrapper",
|
||||
"files": [
|
||||
"https://github.com/kijai/ComfyUI-MimicMotionWrapper"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Optimized wrapper nodes for MimicMotion: [a/https://github.com/tencent/MimicMotion](https://github.com/tencent/MimicMotion)"
|
||||
},
|
||||
{
|
||||
"author": "kijai",
|
||||
"title": "ComfyUI-OpenDiTWrapper",
|
||||
"id": "opendit-kijai",
|
||||
"reference": "https://github.com/kijai/ComfyUI-OpenDiTWrapper",
|
||||
"files": [
|
||||
"https://github.com/kijai/ComfyUI-OpenDiTWrapper"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Wrapper nodes for OpenDiT: [a/OpenDiT](https://github.com/NUS-HPC-AI-Lab/OpenDiT/), supports Open-Sora t2i and i2i"
|
||||
},
|
||||
{
|
||||
"author": "smthemex",
|
||||
"title": "ComfyUI_MS_Diffusion",
|
||||
@ -639,61 +694,6 @@
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Nodes:Load Ultralytics Model, Ultralytics Inference, Ultralytics Visualization, Convert to Dictionary, BBox to XYWH"
|
||||
},
|
||||
{
|
||||
"author": "chris-the-wiz",
|
||||
"title": "EmbeddingsCurveEditor_ComfyUI",
|
||||
"id": "embeddings-curve-editor",
|
||||
"reference": "https://github.com/chris-the-wiz/EmbeddingsCurveEditor_ComfyUI",
|
||||
"files": [
|
||||
"https://github.com/chris-the-wiz/EmbeddingsCurveEditor_ComfyUI"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Edit embeddings with a curve. Actually should work on any 1D input tensor. Tested with IPAdapter-Plus."
|
||||
},
|
||||
{
|
||||
"author": "AustinMroz",
|
||||
"title": "ComfyUI-WorkflowCheckpointing",
|
||||
"id": "workflowcheckpointing",
|
||||
"reference": "https://github.com/AustinMroz/ComfyUI-WorkflowCheckpointing",
|
||||
"files": [
|
||||
"https://github.com/AustinMroz/ComfyUI-WorkflowCheckpointing"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Automatically creates checkpoints during workflow execution. If If an workflow is canceled or ComfyUI crashes mid-execution, then these checkpoints are used when the workflow is re-queued to resume execution with minimal progress loss."
|
||||
},
|
||||
{
|
||||
"author": "TRI3D-LC",
|
||||
"title": "ComfyUI-MiroBoard",
|
||||
"id": "miroboard",
|
||||
"reference": "https://github.com/TRI3D-LC/ComfyUI-MiroBoard",
|
||||
"files": [
|
||||
"https://github.com/TRI3D-LC/ComfyUI-MiroBoard"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Nodes: add-image-miro-board."
|
||||
},
|
||||
{
|
||||
"author": "SamKhoze",
|
||||
"title": "DeepFuze",
|
||||
"id": "deepfuze",
|
||||
"reference": "https://github.com/SamKhoze/ComfyUI-DeepFuze",
|
||||
"files": [
|
||||
"https://github.com/SamKhoze/ComfyUI-DeepFuze"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "DeepFuze is a state-of-the-art deep learning tool that seamlessly integrates with ComfyUI to revolutionize facial transformations, lipsyncing, video generation, voice cloning, face swapping, and lipsync translation. Leveraging advanced algorithms, DeepFuze enables users to combine audio and video with unparalleled realism, ensuring perfectly synchronized facial movements. This innovative solution is ideal for content creators, animators, developers, and anyone seeking to elevate their video editing projects with sophisticated AI-driven features."
|
||||
},
|
||||
{
|
||||
"author": "AIFSH",
|
||||
"title": "ComfyUI-UniAnimate",
|
||||
"id": "unianimate",
|
||||
"reference": "https://github.com/AIFSH/ComfyUI-UniAnimate",
|
||||
"files": [
|
||||
"https://github.com/AIFSH/ComfyUI-UniAnimate"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "a comfyui custom node for [a/UniAnimate](https://github.com/ali-vilab/UniAnimate)"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -1999,7 +1999,9 @@
|
||||
],
|
||||
"https://github.com/GraftingRayman/ComfyUI_GraftingRayman": [
|
||||
[
|
||||
"GR Background Remover REMBG",
|
||||
"GR Checkered Board",
|
||||
"GR Counter",
|
||||
"GR Flip Tile Random Inverted",
|
||||
"GR Flip Tile Random Red Ring",
|
||||
"GR Image Details Displayer",
|
||||
@ -2389,6 +2391,7 @@
|
||||
],
|
||||
"https://github.com/JayLyu/ComfyUI_BaiKong_Node": [
|
||||
[
|
||||
"BK_ColorLimit",
|
||||
"BK_ColorSelector",
|
||||
"BK_GradientImage",
|
||||
"BK_Img2Color"
|
||||
@ -3016,6 +3019,21 @@
|
||||
"title_aux": "Mosaica"
|
||||
}
|
||||
],
|
||||
"https://github.com/MiddleKD/ComfyUI-productfix": [
|
||||
[
|
||||
"ApplyLatentInjection",
|
||||
"DetailTransferAdd",
|
||||
"DetailTransferLatentAdd",
|
||||
"GetTextMask",
|
||||
"ResetModelPatcherCalculateWeight",
|
||||
"VQDecoder",
|
||||
"VQEncoder",
|
||||
"VQLoader"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-productfix"
|
||||
}
|
||||
],
|
||||
"https://github.com/MilitantHitchhiker/MilitantHitchhiker-SwitchbladePack": [
|
||||
[
|
||||
"IntegratedRandomPromptGenerator",
|
||||
@ -3564,6 +3582,7 @@
|
||||
"LatentInsertWithBBox(FaceParsing)",
|
||||
"LatentSize(FaceParsing)",
|
||||
"MaskComposite(FaceParsing)",
|
||||
"MaskInsertWithBBox(FaceParsing)",
|
||||
"MaskListComposite(FaceParsing)",
|
||||
"MaskListSelect(FaceParsing)",
|
||||
"MaskToBBox(FaceParsing)",
|
||||
@ -9803,6 +9822,8 @@
|
||||
"github_tool",
|
||||
"google_tool",
|
||||
"interpreter_tool",
|
||||
"json_get_value",
|
||||
"json_parser",
|
||||
"keyword_tool",
|
||||
"listen_audio",
|
||||
"llama_guff_loader",
|
||||
@ -9832,6 +9853,7 @@
|
||||
"tool_combine",
|
||||
"tool_combine_plus",
|
||||
"weather_tool",
|
||||
"weekday_tool",
|
||||
"wikipedia_tool",
|
||||
"work_wechat",
|
||||
"work_wechat_tool",
|
||||
@ -11189,6 +11211,32 @@
|
||||
"title_aux": "Marigold depth estimation in ComfyUI"
|
||||
}
|
||||
],
|
||||
"https://github.com/kijai/ComfyUI-MimicMotionWrapper": [
|
||||
[
|
||||
"DiffusersScheduler",
|
||||
"DownloadAndLoadMimicMotionModel",
|
||||
"MimicMotionDecode",
|
||||
"MimicMotionGetPoses",
|
||||
"MimicMotionSampler"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-MimicMotionWrapper"
|
||||
}
|
||||
],
|
||||
"https://github.com/kijai/ComfyUI-OpenDiTWrapper": [
|
||||
[
|
||||
"DownloadAndLoadOpenDiTT5Model",
|
||||
"DownloadAndLoadOpenSoraModel",
|
||||
"DownloadAndLoadOpenSoraVAE",
|
||||
"OpenDiTConditioning",
|
||||
"OpenDiTSampler",
|
||||
"OpenSoraDecode",
|
||||
"OpenSoraEncodeReference"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-OpenDiTWrapper"
|
||||
}
|
||||
],
|
||||
"https://github.com/kijai/ComfyUI-SUPIR": [
|
||||
[
|
||||
"SUPIR_Upscale",
|
||||
@ -11460,7 +11508,9 @@
|
||||
"TclExtractFramesFromVideo",
|
||||
"TclExtractFramesFromVideoFile",
|
||||
"TclFrames2Video",
|
||||
"TclSaveVideoFromFrames"
|
||||
"TclSaveVideoFromFrames",
|
||||
"TclYoloV8Segmentation",
|
||||
"TclYoloV9Segmentation"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-TRA"
|
||||
@ -13021,6 +13071,7 @@
|
||||
"ConditioningMultiplier_PoP",
|
||||
"ConditioningNormalizer_PoP",
|
||||
"DallE3_PoP",
|
||||
"EfficientAttention",
|
||||
"LoadImageResizer_PoP",
|
||||
"LoraStackLoader10_PoP",
|
||||
"LoraStackLoader_PoP",
|
||||
@ -13579,6 +13630,14 @@
|
||||
"title_aux": "comfyui-edit-mask"
|
||||
}
|
||||
],
|
||||
"https://github.com/shadowcz007/comfyui-liveportrait": [
|
||||
[
|
||||
"LivePortraitNode"
|
||||
],
|
||||
{
|
||||
"title_aux": "comfyui-liveportrait"
|
||||
}
|
||||
],
|
||||
"https://github.com/shadowcz007/comfyui-mixlab-nodes": [
|
||||
[
|
||||
"3DImage",
|
||||
@ -14600,6 +14659,14 @@
|
||||
"title_aux": "quadmoon's ComfyUI nodes"
|
||||
}
|
||||
],
|
||||
"https://github.com/tritant/ComfyUI_CreaPrompt": [
|
||||
[
|
||||
"CreaPrompt"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-CreaPrompt"
|
||||
}
|
||||
],
|
||||
"https://github.com/trojblue/trNodes": [
|
||||
[
|
||||
"trColorCorrection",
|
||||
|
||||
@ -62,7 +62,7 @@ check_file_logging()
|
||||
|
||||
comfy_path = os.environ.get('COMFYUI_PATH')
|
||||
if comfy_path is None:
|
||||
comfy_path = os.path.abspath(sys.modules['__main__'].__file__)
|
||||
comfy_path = os.path.abspath(os.path.dirname(sys.modules['__main__'].__file__))
|
||||
|
||||
sys.__comfyui_manager_register_message_collapse = register_message_collapse
|
||||
sys.__comfyui_manager_is_import_failed_extension = is_import_failed_extension
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "comfyui-manager"
|
||||
description = "ComfyUI-Manager provides features to install and manage custom nodes for ComfyUI, as well as various functionalities to assist with ComfyUI."
|
||||
version = "2.43"
|
||||
version = "2.44.1"
|
||||
license = "LICENSE"
|
||||
dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions"]
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user