Browse Source

Add alternatives of A1111 menu.

Add local db mode
pull/7/head
Dr.Lt.Data 2 years ago
parent
commit
63af7efa63
  1. 89
      __init__.py
  2. 36
      alter-list.json
  3. 307
      js/comfyui-manager.js

89
__init__.py

@ -14,10 +14,37 @@ print("### Loading: ComfyUI-Manager")
comfy_path = os.path.dirname(folder_paths.__file__)
custom_nodes_path = os.path.join(comfy_path, 'custom_nodes')
comfyui_manager_path = os.path.dirname(__file__)
local_db_model = os.path.join(comfyui_manager_path, "model-list.json")
local_db_alter = os.path.join(comfyui_manager_path, "alter-list.json")
local_db_custom_node_list = os.path.join(comfyui_manager_path, "custom-node-list.json")
async def get_data(uri):
print(f"FECTH DATA from: {uri}")
if uri.startswith("http"):
async with aiohttp.ClientSession() as session:
async with session.get(uri) as resp:
json_text = await resp.text()
else:
with open(uri, "r") as f:
json_text = f.read()
json_obj = json.loads(json_text)
return json_obj
def setup_js():
impact_path = os.path.dirname(__file__)
js_dest_path = os.path.join(comfy_path, "web", "extensions", "core")
js_src_path = os.path.join(impact_path, "js", "comfyui-manager.js")
# remove garbage
old_js_path = os.path.join(comfy_path, "web", "extensions", "core", "comfyui-manager.js")
if os.path.exists(old_js_path):
os.remove(old_js_path)
# setup js
js_dest_path = os.path.join(comfy_path, "web", "extensions", "comfyui-manager")
if not os.path.exists(js_dest_path):
os.makedirs(js_dest_path)
js_src_path = os.path.join(comfyui_manager_path, "js", "comfyui-manager.js")
shutil.copy(js_src_path, js_dest_path)
setup_js()
@ -64,8 +91,7 @@ def get_model_path(data):
return os.path.join(base_model, data['filename'])
def check_custom_node_installed(json_obj):
for item in json_obj['custom_nodes']:
def check_a_custom_node_installed(item):
item['installed'] = 'None'
if item['install_type'] == 'git-clone' and len(item['files']) == 1:
@ -84,20 +110,55 @@ def check_custom_node_installed(json_obj):
else:
item['installed'] = 'False'
def check_custom_nodes_installed(json_obj):
for item in json_obj['custom_nodes']:
check_a_custom_node_installed(item)
@server.PromptServer.instance.routes.post("/customnode/getlist")
@server.PromptServer.instance.routes.get("/customnode/getlist")
async def fetch_customnode_list(request):
url = 'https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/custom-node-list.json'
if request.rel_url.query["mode"] == "local":
uri = local_db_custom_node_list
else:
uri = 'https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/custom-node-list.json'
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
async with session.get(uri) as resp:
json_text = await resp.text()
json_obj = json.loads(json_text)
check_custom_node_installed(json_obj)
check_custom_nodes_installed(json_obj)
return web.json_response(json_obj, content_type='application/json')
@server.PromptServer.instance.routes.get("/alternatives/getlist")
async def fetch_alternatives_list(request):
if request.rel_url.query["mode"] == "local":
uri1 = local_db_alter
uri2 = local_db_custom_node_list
else:
uri1 = 'https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/alter-list.json'
uri2 = 'https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/custom-node-list.json'
alter_json = await get_data(uri1)
custom_node_json = await get_data(uri2)
fileurl_to_custom_node = {}
for item in custom_node_json['custom_nodes']:
for fileurl in item['files']:
fileurl_to_custom_node[fileurl] = item
for item in alter_json['items']:
fileurl = item['id']
if fileurl in fileurl_to_custom_node:
custom_node = fileurl_to_custom_node[fileurl]
check_a_custom_node_installed(custom_node)
item['custom_node'] = custom_node
return web.json_response(alter_json, content_type='application/json')
def check_model_installed(json_obj):
for item in json_obj['models']:
item['installed'] = 'None'
@ -111,11 +172,15 @@ def check_model_installed(json_obj):
item['installed'] = 'False'
@server.PromptServer.instance.routes.post("/externalmodel/getlist")
@server.PromptServer.instance.routes.get("/externalmodel/getlist")
async def fetch_externalmodel_list(request):
url = 'https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/model-list.json'
if request.rel_url.query["mode"] == "local":
uri = local_db_model
else:
uri = 'https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/model-list.json'
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
async with session.get(uri) as resp:
json_text = await resp.text()
json_obj = json.loads(json_text)

36
alter-list.json

@ -3,99 +3,71 @@
{
"id":"https://github.com/Fannovel16/comfy_controlnet_preprocessors",
"tags":"controlnet",
"author":"Fannovel16",
"title":"ControlNet Preprocessors",
"description": "This extension provides preprocessor nodes for using controlnet."
},
{
"id":"https://github.com/comfyanonymous/ComfyUI_experiments",
"id":"https://github.com/comfyanonymous/ComfyUI_experiments/raw/master/sampler_tonemap.py",
"tags":"Dynamic Thresholding, DT",
"author":"comfyanonymous",
"title":"ComfyUI_experiments/sampler_tonemap",
"description": "Increasing the CFG prevents the degradation of color accuracy."
},
{
"id":"https://github.com/ltdrdata/ComfyUI-Impact-Pack",
"tags":"ddetailer, adetailer, ddsd, DD",
"author":"Dr.Lt.Data",
"title":"ComfyUI Impact Pack",
"description": "To implement the feature of automatically detecting faces and enhancing details, various detection nodes and detailers provided by the Impact Pack can be applied."
},
{
"id":"https://github.com/biegert/ComfyUI-CLIPSeg",
"id":"https://github.com/biegert/ComfyUI-CLIPSeg/raw/main/custom_nodes/clipseg.py",
"tags":"ddsd",
"author":"biegert",
"title":"CLIPSeg",
"description": "This extension provides a feature that generates segment masks on an image using a text prompt. When used in conjunction with Impact Pack, it enables applications such as DDSD."
},
{
"id":"https://github.com/BadCafeCode/masquerade-nodes-comfyui",
"tags":"ddetailer",
"author":"BadCafeCode",
"title":"Masquerade Nodes",
"description": "This extension provides a way to recognize and enhance masks for faces similar to Impact Pack."
},
{
"id":"https://github.com/BlenderNeko/ComfyUI_Cutoff",
"tags":"cutoff",
"author":"BlenderNeko",
"title":"ComfyUI Cutoff",
"description": "By using this extension, prompts like 'blue hair' can be prevented from interfering with other prompts by blocking the attribute 'blue' from being used in prompts other than 'hair'."
},
{
"id":"https://github.com/BlenderNeko/ComfyUI_ADV_CLIP_emb",
"tags":"prompt, weight",
"author":"BlenderNeko",
"title":"Advanced CLIP Text Encode",
"description": "There are differences in the processing methods of prompts, such as weighting and scheduling, between A1111 and ComfyUI. With this extension, various settings can be used to implement prompt processing methods similar to A1111. As this feature is also integrated into ComfyUI Cutoff, please download the Cutoff extension if you plan to use it in conjunction with Cutoff."
},
{
"id":"https://github.com/BlenderNeko/ComfyUI_Noise",
"tags":"img2img alt",
"author":"BlenderNeko",
"title":"ComfyUI Noise",
"description": "The extension provides an unsampler that reverses the sampling process, allowing for a function similar to img2img alt to be implemented."
"tags":"img2img alt, random",
"description": "The extension provides an unsampler that reverses the sampling process, allowing for a function similar to img2img alt to be implemented. Furthermore, ComfyUI uses CPU's Random instead of GPU's Random for better reproducibility compared to A1111. This extension provides the ability to use GPU's Random for Latent Noise. However, since GPU's Random may vary depending on the GPU model, reproducibility on different devices cannot be guaranteed."
},
{
"id":"https://github.com/lilly1987/ComfyUI_node_Lilly",
"tags":"prompt, wildcard",
"author":"lilly1987",
"title":"simple wildcard for ComfyUI",
"description": "This extension provides features such as a wildcard function that randomly selects prompts belonging to a category and the ability to directly load lora from prompts."
},
{
"id":"https://github.com/Davemane42/ComfyUI_Dave_CustomNode",
"tags":"latent couple",
"author":"Davemane42",
"title":"Visual Area Conditioning / Latent composition",
"description": "ComfyUI already provides the ability to composite latents by default. However, this extension makes it more convenient to use by visualizing the composite area."
},
{
"id":"https://github.com/LEv145/images-grid-comfy-plugin",
"tags":"X/Y Plot",
"author":"LEv145",
"title":"ImagesGrid",
"description": "This tool provides a viewer node that allows for checking multiple outputs in a grid, similar to the X/Y Plot extension."
},
{
"id":"https://github.com/gamert/ComfyUI_tagger",
"tags":"deepbooru, clip interrogation",
"author":"gamert",
"title":"ComfyUI_tagger",
"description": "This extension generates clip text by taking an image as input and using the Deepbooru model."
},
{
"id":"https://github.com/szhublox/ambw_comfyui",
"tags":"supermerger",
"author":"szhublox",
"title":"Auto-MBW",
"description": "This node takes two models, merges individual blocks together at various ratios, and automatically rates each merge, keeping the ratio with the highest score. "
},
{
"id":"https://github.com/asd417/tomeSD_for_Comfy/raw/main/tomeloader.py",
"tags":"tomesd",
"author":"szhublox",
"title":"Auto-MBW",
"description": "This extension is a ComfyUI wrapper for 'tomesd' that improves generation speed through token merging."
}
]

307
js/comfyui-manager.js vendored

@ -3,30 +3,41 @@ import { ComfyDialog, $el } from "/scripts/ui.js";
import {ComfyWidgets} from "../../scripts/widgets.js";
async function getCustomNodes() {
const response = await fetch('/customnode/getlist', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({})
});
var mode = "url";
if(ManagerMenuDialog.instance.local_mode_checkbox.checked)
mode = "local";
const response = await fetch(`/customnode/getlist?mode=${mode}`);
const data = await response.json();
return data;
}
async function getAlterList() {
var mode = "url";
if(ManagerMenuDialog.instance.local_mode_checkbox.checked)
mode = "local";
const response = await fetch(`/alternatives/getlist?mode=${mode}`);
const data = await response.json();
return data;
}
async function getModelList() {
const response = await fetch('/externalmodel/getlist', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({})
});
var mode = "url";
if(ManagerMenuDialog.instance.local_mode_checkbox.checked)
mode = "local";
const response = await fetch(`/externalmodel/getlist?mode=${mode}`);
const data = await response.json();
return data;
}
async function install_custom_node(target) {
if(CustomNodesInstaller.instance) {
CustomNodesInstaller.instance.startInstall(target);
async function install_custom_node(target, caller) {
if(caller) {
caller.startInstall(target);
try {
const response = await fetch('/customnode/install', {
@ -46,7 +57,7 @@ async function install_custom_node(target) {
return false;
}
finally {
CustomNodesInstaller.instance.stopInstall();
caller.invalidateControl();
}
}
}
@ -73,12 +84,13 @@ async function install_model(target) {
return false;
}
finally {
ModelInstaller.instance.stopInstall();
ModelInstaller.instance.invalidateControl();
}
}
}
// -----
class CustomNodesInstaller extends ComfyDialog {
static instance = null;
@ -98,7 +110,6 @@ class CustomNodesInstaller extends ComfyDialog {
}
startInstall(target) {
console.log(target);
this.message_box.innerHTML = `<BR><font color="green">Installing '${target.title}'</font>`;
for(let i in this.install_buttons) {
@ -107,29 +118,16 @@ class CustomNodesInstaller extends ComfyDialog {
}
}
stopInstall() {
this.message_box.innerHTML = '<BR>To apply the installed custom node, please restart ComfyUI.';
async invalidateControl() {
this.clear();
this.data = (await getCustomNodes()).custom_nodes;
for(let i in this.install_buttons) {
switch(this.data[i].installed)
{
case 'True':
this.install_buttons[i].innerHTML = 'Installed';
this.install_buttons[i].style.backgroundColor = 'green';
this.install_buttons[i].disabled = true;
break;
case 'False':
this.install_buttons[i].innerHTML = 'Install';
this.install_buttons[i].style.backgroundColor = 'black';
this.install_buttons[i].disabled = false;
break;
default:
this.install_buttons[i].innerHTML = 'Try Install';
this.install_buttons[i].style.backgroundColor = 'brown';
this.install_buttons[i].disabled = false;
break;
}
while (this.element.children.length) {
this.element.removeChild(this.element.children[0]);
}
await this.createGrid();
this.createControls();
}
async createGrid() {
@ -205,7 +203,7 @@ class CustomNodesInstaller extends ComfyDialog {
}
installBtn.addEventListener('click', function() {
install_custom_node(data);
install_custom_node(data, CustomNodesInstaller.instance);
});
data5.appendChild(installBtn);
@ -247,8 +245,47 @@ class CustomNodesInstaller extends ComfyDialog {
async show() {
try {
this.invalidateControl();
this.element.style.display = "block";
}
catch(exception) {
app.ui.dialog.show(`Failed to get custom node list. / ${exception}`);
}
}
}
// -----
class AlternativesInstaller extends ComfyDialog {
static instance = null;
install_buttons = [];
message_box = null;
data = null;
clear() {
this.install_buttons = [];
this.message_box = null;
this.data = null;
}
constructor() {
super();
this.element = $el("div.comfy-modal", { parent: document.body }, []);
}
startInstall(target) {
this.message_box.innerHTML = `<BR><font color="green">Installing '${target.title}'</font>`;
for(let i in this.install_buttons) {
this.install_buttons[i].disabled = true;
this.install_buttons[i].style.backgroundColor = 'gray';
}
}
async invalidateControl() {
this.clear();
this.data = (await getCustomNodes()).custom_nodes;
this.data = (await getAlterList()).items;
while (this.element.children.length) {
this.element.removeChild(this.element.children[0]);
@ -256,14 +293,149 @@ class CustomNodesInstaller extends ComfyDialog {
await this.createGrid();
this.createControls();
}
async createGrid() {
var grid = document.createElement('table');
grid.setAttribute('id', 'alternatives-grid');
grid.style.position = "relative";
grid.style.display = "inline-block";
grid.style.width = "100%"
var headerRow = document.createElement('tr');
var header1 = document.createElement('th');
header1.innerHTML = '&nbsp;&nbsp;ID&nbsp;&nbsp;';
header1.style.width = "20px";
var header2 = document.createElement('th');
header2.innerHTML = 'Tags';
header2.style.width = "200px";
var header3 = document.createElement('th');
header3.innerHTML = 'Author';
header3.style.width = "150px";
var header4 = document.createElement('th');
header4.innerHTML = 'Title';
header4.style.width = "200px";
var header5 = document.createElement('th');
header5.innerHTML = 'Description';
header5.style.width = "500px";
var header6 = document.createElement('th');
header6.innerHTML = 'Install';
header6.style.width = "130px";
headerRow.appendChild(header1);
headerRow.appendChild(header2);
headerRow.appendChild(header3);
headerRow.appendChild(header4);
headerRow.appendChild(header5);
headerRow.appendChild(header6);
headerRow.style.backgroundColor = "Black";
headerRow.style.color = "White";
headerRow.style.textAlign = "center";
headerRow.style.width = "100%";
headerRow.style.padding = "0";
grid.appendChild(headerRow);
if(this.data)
for (var i = 0; i < this.data.length; i++) {
const data = this.data[i];
var dataRow = document.createElement('tr');
var data1 = document.createElement('td');
data1.style.textAlign = "center";
data1.innerHTML = i+1;
var data2 = document.createElement('td');
data2.innerHTML = `&nbsp;${data.tags}`;
var data3 = document.createElement('td');
var data4 = document.createElement('td');
if(data.custom_node) {
data3.innerHTML = `&nbsp;${data.custom_node.author}`;
data4.innerHTML = `&nbsp;<a href=${data.custom_node.reference} target="_blank"><font color="skyblue"><b>${data.custom_node.title}</b></font></a>`;
}
else {
data3.innerHTML = `&nbsp;Unknown`;
data4.innerHTML = `&nbsp;Unknown`;
}
var data5 = document.createElement('td');
data5.innerHTML = data.description;
var data6 = document.createElement('td');
data6.style.textAlign = "center";
if(data.custom_node) {
var installBtn = document.createElement('button');
this.install_buttons.push(installBtn);
switch(data.custom_node.installed) {
case 'True':
installBtn.innerHTML = 'Installed';
installBtn.style.backgroundColor = 'green';
installBtn.disabled = true;
break;
case 'False':
installBtn.innerHTML = 'Install';
installBtn.style.backgroundColor = 'black';
break;
default:
installBtn.innerHTML = 'Try Install';
installBtn.style.backgroundColor = 'brown';
}
installBtn.addEventListener('click', function() {
install_custom_node(data.custom_node, AlternativesInstaller.instance);
});
data6.appendChild(installBtn);
}
dataRow.style.backgroundColor = "#444444";
dataRow.style.color = "White";
dataRow.style.textAlign = "left";
dataRow.appendChild(data1);
dataRow.appendChild(data2);
dataRow.appendChild(data3);
dataRow.appendChild(data4);
dataRow.appendChild(data5);
dataRow.appendChild(data6);
grid.appendChild(dataRow);
}
const panel = document.createElement('div');
panel.style.height = "400px";
panel.style.width = "1000px";
panel.style.overflowY = "scroll";
panel.appendChild(grid);
this.element.appendChild(panel);
}
async createControls() {
var close_button = document.createElement("button");
close_button.innerHTML = "Close";
close_button.onclick = () => { this.close(); }
close_button.style.display = "inline-block";
this.message_box = $el('div', {id:'alternatives-installer-message'}, [$el('br'), '']);
this.message_box.style.height = '60px';
this.message_box.style.verticalAlign = 'middle';
this.element.appendChild(this.message_box);
this.element.appendChild(close_button);
}
async show() {
try {
this.invalidateControl();
this.element.style.display = "block";
}
catch(exception) {
app.ui.dialog.show(`Failed to get custom node list. / ${exception}`);
app.ui.dialog.show(`Failed to get alternatives list. / ${exception}`);
console.error(exception);
}
}
}
// -----------
class ModelInstaller extends ComfyDialog {
static instance = null;
@ -302,24 +474,16 @@ class ModelInstaller extends ComfyDialog {
}
}
stopInstall() {
this.message_box.innerHTML = "<BR>To apply the installed model, please click the 'Refresh' button on the main menu.";
async invalidateControl() {
this.clear();
this.data = (await getModelList()).models;
for(let i in this.install_buttons) {
switch(this.data[i].installed)
{
case 'True':
this.install_buttons[i].innerHTML = 'Installed';
this.install_buttons[i].style.backgroundColor = 'green';
this.install_buttons[i].disabled = true;
break;
default:
this.install_buttons[i].innerHTML = 'Install';
this.install_buttons[i].style.backgroundColor = 'black';
this.install_buttons[i].disabled = false;
break;
}
while (this.element.children.length) {
this.element.removeChild(this.element.children[0]);
}
await this.createGrid();
this.createControls();
}
async createGrid(models_json) {
@ -452,15 +616,7 @@ class ModelInstaller extends ComfyDialog {
async show() {
try {
this.clear();
this.data = (await getModelList()).models;
while (this.element.children.length) {
this.element.removeChild(this.element.children[0]);
}
await this.createGrid();
this.createControls();
this.invalidateControl();
this.element.style.display = "block";
}
catch(exception) {
@ -469,15 +625,22 @@ class ModelInstaller extends ComfyDialog {
}
}
// -----------
class ManagerMenuDialog extends ComfyDialog {
static instance = null;
local_mode_checkbox = null;
createButtons() {
this.local_mode_checkbox = $el("input",{type:'checkbox', id:"use_local_db"},[])
const checkbox_text = $el("label",{},["Use local DB"])
checkbox_text.style.color = "var(--fg-color)"
const res =
[
$el("tr.td", {width:"100%"}, [$el("font", {size:6, color:"white"}, ["Manager Menu"])]),
$el("br", {}, []),
$el("div", {}, [this.local_mode_checkbox, checkbox_text]),
$el("button", {
type: "button",
textContent: "Install Custom Nodes",
@ -500,6 +663,19 @@ class ManagerMenuDialog extends ComfyDialog {
}
}),
$el("br", {}, []),
$el("button", {
type: "button",
textContent: "Alternatives of A1111",
onclick:
() => {
if(!AlternativesInstaller.instance)
AlternativesInstaller.instance = new AlternativesInstaller(app);
AlternativesInstaller.instance.show();
}
}),
$el("br", {}, []),
$el("button", {
type: "button",
textContent: "Close",
@ -507,7 +683,6 @@ class ManagerMenuDialog extends ComfyDialog {
})
];
console.log(res);
res[0].style.backgroundColor = "black";
res[0].style.textAlign = "center";
res[0].style.height = "45px";

Loading…
Cancel
Save