Add live update workflow node from sub workflow inputs/outputs
This commit is contained in:
@@ -58,7 +58,7 @@ Warning and know issue:
|
||||
|
||||
## 🔗 requirements
|
||||
|
||||
- **comfyui**: Be sure to have a **ComfyUI front-end** version of at least **1.3.11**. If not, update ComfyUI to the latest version. To find the front-end version, go to ComfyUI settings (the gear icon), click "About," and check the version at the top of the page.
|
||||
- **comfyui**: Be sure to have a **ComfyUI front-end** version of at least **1.11.8**. If not, update ComfyUI to the latest version. To find the front-end version, go to ComfyUI settings (the gear icon), click "About," and check the version at the top of the page.
|
||||
|
||||
## 💻 Installation
|
||||
|
||||
|
||||
+37
-72
@@ -5,6 +5,37 @@ import json
|
||||
import folder_paths
|
||||
from app.user_manager import UserManager
|
||||
|
||||
def get_workflow_data(workflow_file):
|
||||
nodes_input = {}
|
||||
nodes_output = {}
|
||||
|
||||
if "nodes" in workflow_file:
|
||||
# Extraire les nœuds WorkflowInput et WorkflowOutput
|
||||
for node in workflow_file["nodes"]:
|
||||
if node.get("type") == "WorkflowInput":
|
||||
# Convertir au format compatible pour le client
|
||||
node_id = str(node.get("id", "unknown"))
|
||||
nodes_input[node_id] = {
|
||||
"class_type": "WorkflowInput",
|
||||
"inputs": node.get("widgets_values", {}),
|
||||
"position": node.get("pos", {})[1]
|
||||
}
|
||||
elif node.get("type") == "WorkflowOutput":
|
||||
node_id = str(node.get("id", "unknown"))
|
||||
nodes_output[node_id] = {
|
||||
"class_type": "WorkflowOutput",
|
||||
"inputs": node.get("widgets_values", {}),
|
||||
"position": node.get("pos", {})[1]
|
||||
}
|
||||
# sort by position
|
||||
nodes_input = dict(sorted(nodes_input.items(), key=lambda item: item[1]["position"]))
|
||||
nodes_output = dict(sorted(nodes_output.items(), key=lambda item: item[1]["position"]))
|
||||
|
||||
if nodes_input or nodes_output:
|
||||
# Créer une clé unique basée sur le chemin relatif
|
||||
return {"inputs": nodes_input,
|
||||
"outputs": nodes_output,
|
||||
'workflow': workflow_file}
|
||||
|
||||
@server.PromptServer.instance.routes.get("/flowchain/workflows")
|
||||
async def workflows(request):
|
||||
@@ -24,45 +55,9 @@ async def workflows(request):
|
||||
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
json_content = json.load(f)
|
||||
|
||||
nodes_input = {}
|
||||
nodes_output = {}
|
||||
|
||||
|
||||
# Vérifier le format du workflow (API ou standard)
|
||||
if "nodes" in json_content:
|
||||
# Format standard (non-API)
|
||||
is_standard_format = True
|
||||
|
||||
# Extraire les nœuds WorkflowInput et WorkflowOutput
|
||||
for node in json_content["nodes"]:
|
||||
if node.get("type") == "WorkflowInput":
|
||||
# Convertir au format compatible pour le client
|
||||
node_id = str(node.get("id", "unknown"))
|
||||
nodes_input[node_id] = {
|
||||
"class_type": "WorkflowInput",
|
||||
"inputs": node.get("widgets_values", {})
|
||||
}
|
||||
elif node.get("type") == "WorkflowOutput":
|
||||
node_id = str(node.get("id", "unknown"))
|
||||
nodes_output[node_id] = {
|
||||
"class_type": "WorkflowOutput",
|
||||
"inputs": node.get("widgets_values", {})
|
||||
}
|
||||
else:
|
||||
# Format API
|
||||
nodes_input = {k: v for k, v in json_content.items() if
|
||||
v.get("class_type") == "WorkflowInput"}
|
||||
nodes_output = {k: v for k, v in json_content.items() if
|
||||
v.get("class_type") == "WorkflowOutput"}
|
||||
|
||||
# Ajouter au résultat seulement si le fichier contient des nœuds WorkflowInput ou WorkflowOutput
|
||||
if nodes_input or nodes_output:
|
||||
# Créer une clé unique basée sur le chemin relatif
|
||||
relative_path = os.path.relpath(file_path, json_path)
|
||||
result[relative_path] = {"inputs": nodes_input,
|
||||
"outputs": nodes_output,
|
||||
'workflow': json_content}
|
||||
relative_path = os.path.relpath(file_path, json_path)
|
||||
result[relative_path] = get_workflow_data(json_content)
|
||||
|
||||
except json.JSONDecodeError:
|
||||
# Ignorer les fichiers JSON mal formés
|
||||
print(f"Ignoring malformed JSON file: {file_path}")
|
||||
@@ -88,45 +83,15 @@ async def workflow(request):
|
||||
unversal_path = original_path.replace("\\", "/")
|
||||
json_path = unversal_path.split("/")
|
||||
if ".json" in json_path[-1]:
|
||||
file_name = json_path[-1]
|
||||
#file_name = json_path[-1]
|
||||
json_path = folder_paths.user_directory + "/" + user + "/workflows/" + unversal_path
|
||||
|
||||
|
||||
if os.path.exists(json_path):
|
||||
with open(json_path, "r", encoding="utf-8") as f:
|
||||
json_content = json.load(f)
|
||||
|
||||
nodes_input = {}
|
||||
nodes_output = {}
|
||||
|
||||
# Vérifier le format du workflow (API ou standard)
|
||||
if "nodes" in json_content:
|
||||
# Extraire les nœuds WorkflowInput et WorkflowOutput
|
||||
for node in json_content["nodes"]:
|
||||
if node.get("type") == "WorkflowInput":
|
||||
# Convertir au format compatible pour le client
|
||||
node_id = str(node.get("id", "unknown"))
|
||||
nodes_input[node_id] = {
|
||||
"class_type": "WorkflowInput",
|
||||
"inputs": node.get("widgets_values", {})
|
||||
}
|
||||
elif node.get("type") == "WorkflowOutput":
|
||||
node_id = str(node.get("id", "unknown"))
|
||||
nodes_output[node_id] = {
|
||||
"class_type": "WorkflowOutput",
|
||||
"inputs": node.get("widgets_values", {})
|
||||
}
|
||||
else:
|
||||
# Format API
|
||||
nodes_input = {k: v for k, v in json_content.items() if
|
||||
v.get("class_type") == "WorkflowInput"}
|
||||
nodes_output = {k: v for k, v in json_content.items() if
|
||||
v.get("class_type") == "WorkflowOutput"}
|
||||
|
||||
# Ajouter au résultat seulement si le fichier contient des nœuds WorkflowInput ou WorkflowOutput
|
||||
if nodes_input or nodes_output:
|
||||
result = {"inputs": nodes_input,
|
||||
"outputs": nodes_output,
|
||||
'workflow': json_content}
|
||||
result = get_workflow_data(json_content)
|
||||
else:
|
||||
result = {"error": "File not found"}
|
||||
|
||||
|
||||
+384
-366
@@ -274,14 +274,7 @@ function addLoadVideoCommon(nodeType, nodeData) {
|
||||
addPreviewOptions(nodeType);
|
||||
}
|
||||
function cleanInputs(root_obj, start_index = 2, reset_value=true) {
|
||||
//nodeData.input.required = {};
|
||||
/*
|
||||
if (!root_obj.inputs) root_obj.inputs = [];
|
||||
if (!root_obj.outputs) root_obj.outputs = [];
|
||||
if (!root_obj.widgets) root_obj.widgets = [];
|
||||
if (!root_obj.widgets_values) root_obj.widgets_values = [];
|
||||
*/
|
||||
// Disconnect all links first
|
||||
|
||||
for (let i = 0; i < root_obj.outputs.length; i++) {
|
||||
const output = root_obj.outputs[i];
|
||||
if (output.links && output.links.length) {
|
||||
@@ -305,12 +298,6 @@ function cleanInputs(root_obj, start_index = 2, reset_value=true) {
|
||||
root_obj.widgets = root_obj.widgets.splice(0,start_index)
|
||||
if(reset_value){
|
||||
root_obj.widgets_values = [];
|
||||
/*
|
||||
for (let key in root_obj.widgets_values) {
|
||||
if (key != "workflows"){
|
||||
delete root_obj.widgets_values[key];
|
||||
}
|
||||
}*/
|
||||
const max_node_output = root_obj.outputs.length;
|
||||
for(let i = 0; i<max_node_output; i++)
|
||||
root_obj.removeOutput(0)
|
||||
@@ -319,11 +306,6 @@ function cleanInputs(root_obj, start_index = 2, reset_value=true) {
|
||||
const max_node_input = root_obj.inputs.length;
|
||||
for(let i = 0; i<max_node_input; i++)
|
||||
root_obj.removeInput(0)
|
||||
/*
|
||||
if (root_obj.graph) {
|
||||
root_obj.graph.setDirtyCanvas(true);
|
||||
root_obj.graph.change();
|
||||
}*/
|
||||
|
||||
}
|
||||
function clearInputs(root_obj, reset_value=true) {
|
||||
@@ -375,70 +357,7 @@ function clearInputs(root_obj, reset_value=true) {
|
||||
}*/
|
||||
|
||||
}
|
||||
/*
|
||||
function addWidgetType(root_obj, value, nodeData){
|
||||
if (!root_obj.widgets) {
|
||||
root_obj.widgets = [];
|
||||
}
|
||||
if (!root_obj.inputs) {
|
||||
root_obj.inputs = [];
|
||||
}
|
||||
const field_name = value.Name
|
||||
const type = value.type
|
||||
if (type == "IMAGE" && root_obj.inputs.filter(i => i.name === field_name).length == 0){
|
||||
root_obj.addInput(field_name, "IMAGE");
|
||||
|
||||
}
|
||||
|
||||
//const input_value = root_obj.widgets.length + 1 < root_obj.widgets_values.length?root_obj.widgets_values[root_obj.widgets.length]:value.default;
|
||||
if (type == "STRING" || type =="text"){
|
||||
ComfyWidgets.STRING(root_obj, field_name, ['STRING', {default: value.default},], app,)
|
||||
if (nodeData.input.required == undefined) nodeData.input.required = {};
|
||||
//nodeData.input.required[field_name] = ["STRING", {"min": 0, "max": 18446744073709551616, "step": 1}]
|
||||
root_obj.local_input_defs.required[field_name] = ["STRING", {}];
|
||||
|
||||
}
|
||||
|
||||
if (type == "INT"){
|
||||
ComfyWidgets.INT(
|
||||
root_obj,
|
||||
field_name,
|
||||
['INT',{default: value.default},], app,)
|
||||
if (nodeData.input.required == undefined) nodeData.input.required = {};
|
||||
//nodeData.input.required[field_name] = ["INT", {"min": 0, "max": 18446744073709551616, "step": 1}]
|
||||
root_obj.local_input_defs.required[field_name] = ["INT", {"min": 0, "max": 18446744073709551616, "step": 1}];
|
||||
|
||||
|
||||
}
|
||||
if (type == "FLOAT"){
|
||||
ComfyWidgets.FLOAT(
|
||||
root_obj,
|
||||
field_name,
|
||||
['FLOAT',{default: value.default, "min": 0.00, "max": 2048.00, "step": 0.01},],
|
||||
app,
|
||||
)
|
||||
if (nodeData.input.required == undefined) nodeData.input.required = {};
|
||||
//nodeData.input.required[field_name] = ["FLOAT", {"min": 0.00, "max": 2048.00, "step": 0.01}]
|
||||
root_obj.local_input_defs.required[field_name] = ["FLOAT", {"min": 0.00, "max": 2048.00, "step": 0.01}];
|
||||
|
||||
}
|
||||
|
||||
if (type == "BOOLEAN"){
|
||||
root_obj.addWidget("toggle",field_name, value.default, ()=>{});
|
||||
const widget = root_obj.inputs.filter(i => i.name === field_name);
|
||||
if(widget.length > 0)
|
||||
app.convertToWidget(root_obj, widget[0]);
|
||||
}
|
||||
|
||||
if (type == "LATENT") root_obj.addInput(field_name, "LATENT");
|
||||
if (type == "MODEL") root_obj.addInput(field_name, "MODEL");
|
||||
if (type == "CLIP") root_obj.addInput(field_name, "CLIP");
|
||||
if (type == "MASK") root_obj.addInput(field_name, "MASK");
|
||||
if (type == "CONDITIONING") root_obj.addInput(field_name, "CONDITIONING");
|
||||
if (type == "VAE") root_obj.addInput(field_name, "VAE");
|
||||
}
|
||||
|
||||
*/
|
||||
async function convertWorkflowToApiFormat(standardWorkflow) {
|
||||
try {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -552,30 +471,6 @@ async function importWorkflow(root_obj, workflow_path, app, nodeData, reset_valu
|
||||
console.error('Workflow invalide ou échec de conversion');
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
// Traiter le workflow API
|
||||
const nodes_input = Object.fromEntries(
|
||||
Object.entries(workflow).filter(([k, v]) => v.class_type == "WorkflowInput")
|
||||
);
|
||||
|
||||
const nodes_output = Object.fromEntries(
|
||||
Object.entries(workflow).filter(([k, v]) => v.class_type == "WorkflowOutput")
|
||||
);
|
||||
root_obj.widgets[1].value = JSON.stringify(workflow);
|
||||
|
||||
|
||||
Object.entries(nodes_input).forEach(node => {
|
||||
addWidgetType(root_obj, node[1].inputs, nodeData);
|
||||
});
|
||||
|
||||
// Ajouter les sorties
|
||||
Object.entries(nodes_output).forEach(node => {
|
||||
root_obj.addOutput(`${node[1].inputs.Name}`, node[1].inputs.type);
|
||||
});
|
||||
|
||||
|
||||
|
||||
root_obj.size[0] = 400;*/
|
||||
return JSON.stringify(workflow);
|
||||
|
||||
})
|
||||
@@ -600,45 +495,45 @@ function addWidgets(root_obj, field_name, value, app){
|
||||
}
|
||||
|
||||
if ((type == "STRING" || type =="text") && field_name != "workflow"){
|
||||
ComfyWidgets.STRING(root_obj, field_name, ['STRING',{default: value.value,},],app,)
|
||||
ComfyWidgets.STRING(root_obj, field_name, ['STRING', getDefaultOptions("STRING", value.value),],app,)
|
||||
// Stocker la définition localement au lieu de modifier nodeData
|
||||
root_obj.local_input_defs.required[field_name] = ["STRING", {}];
|
||||
root_obj.local_input_defs.required[field_name] = ["STRING", getDefaultOptions("STRING", value.value)];
|
||||
}
|
||||
|
||||
if (type == "INT" || type == "number"){
|
||||
ComfyWidgets.INT(
|
||||
root_obj,
|
||||
field_name,
|
||||
['INT',{default: value.value, "min": 0, "max": 18446744073709551616, "step": 1},],
|
||||
['INT', getDefaultOptions("INT", value.value),],
|
||||
app,
|
||||
)
|
||||
// Stocker la définition localement
|
||||
root_obj.local_input_defs.required[field_name] = ["INT", {"min": 0, "max": 18446744073709551616, "step": 1}];
|
||||
root_obj.local_input_defs.required[field_name] = ["INT", getDefaultOptions("INT", value.value)];
|
||||
}
|
||||
|
||||
if (type == "FLOAT"){
|
||||
ComfyWidgets.FLOAT(
|
||||
root_obj,
|
||||
field_name,
|
||||
['FLOAT',{default: value.value, "min": 0.00, "max": 2048.00, "step": 0.01},],
|
||||
['FLOAT',getDefaultOptions("FLOAT", value.value),],
|
||||
app,
|
||||
)
|
||||
// Stocker la définition localement
|
||||
root_obj.local_input_defs.required[field_name] = ["FLOAT", {"min": 0.00, "max": 2048.00, "step": 0.01}];
|
||||
root_obj.local_input_defs.required[field_name] = ["FLOAT", getDefaultOptions("FLOAT", value.value)];
|
||||
}
|
||||
|
||||
if (type == "BOOLEAN" || type == "toggle"){
|
||||
root_obj.addWidget("toggle",field_name, value.value, ()=>{});
|
||||
// Stocker la définition localement
|
||||
root_obj.local_input_defs.required[field_name] = ["BOOLEAN", {}];
|
||||
root_obj.local_input_defs.required[field_name] = ["BOOLEAN", getDefaultOptions("BOOLEAN", value.value)];
|
||||
}
|
||||
|
||||
/*
|
||||
if (field_name == "workflow"){
|
||||
root_obj.addWidget("STRING", field_name, value.value, ()=>{});
|
||||
root_obj.widgets[root_obj.widgets.length - 1].hidden = true;
|
||||
// Stocker la définition localement
|
||||
root_obj.local_input_defs.required[field_name] = ["STRING", {}];
|
||||
}
|
||||
}*/
|
||||
if (type == "IMAGE") root_obj.addInput(field_name, "IMAGE");
|
||||
if (type == "LATENT") root_obj.addInput(field_name, "LATENT");
|
||||
if (type == "MODEL") root_obj.addInput(field_name, "MODEL");
|
||||
@@ -656,6 +551,7 @@ function addOutputs(root_obj, workflow_name){
|
||||
root_obj.addOutput(value.inputs.Name.value, value.inputs.type.value);
|
||||
}
|
||||
}
|
||||
organizeOutputs(root_obj, workflow_name);
|
||||
}
|
||||
|
||||
// change
|
||||
@@ -699,8 +595,6 @@ function hideWidget(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Hide any linked widgets, e.g. seed+seedControl
|
||||
if (widget.linkedWidgets) {
|
||||
for (const w of widget.linkedWidgets) {
|
||||
@@ -709,27 +603,11 @@ function hideWidget(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getWidgetType(config) {
|
||||
// Special handling for COMBO so we restrict links based on the entries
|
||||
let type = config[0]
|
||||
if (type instanceof Array) {
|
||||
type = 'COMBO'
|
||||
}
|
||||
return { type }
|
||||
}
|
||||
|
||||
const GET_CONFIG = Symbol()
|
||||
|
||||
export function convertToInput(
|
||||
node,
|
||||
widget,
|
||||
config
|
||||
widget
|
||||
) {
|
||||
hideWidget(node, widget)
|
||||
|
||||
const { type } = getWidgetType(config)
|
||||
|
||||
// Add input and store widget config for creating on primitive node
|
||||
const [oldWidth, oldHeight] = node.size
|
||||
|
||||
@@ -744,34 +622,358 @@ function hideWidget(
|
||||
])
|
||||
return node
|
||||
}
|
||||
|
||||
export function addInputs(root_obj, inputs, widgets_values){
|
||||
|
||||
|
||||
let start_index = 2;
|
||||
for (let [key, value] of Object.entries(inputs)){
|
||||
const isinput = root_obj.inputs.find(i => i.name == value.inputs[0]);
|
||||
const isWidget = root_obj.widgets.find(w => w.name == value.inputs[0]);
|
||||
export function getDefaultOptions(type, value = 0){
|
||||
let options = {};
|
||||
switch(type){
|
||||
case "INT":
|
||||
options = {default: value, "min": 0, "max": 18446744073709551616, "step": 1};
|
||||
break;
|
||||
case "FLOAT":
|
||||
options = {default: value, "min": 0.00, "max": 2048.00, "step": 0.01};
|
||||
break;
|
||||
default:
|
||||
options = {};
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
export function addInputs(node, inputs, widgets_values, initial = false) {
|
||||
// Phase 1: Préparer les données triées et simplifiées
|
||||
const mapped_input = Object.entries(inputs)
|
||||
.sort(([, a], [, b]) => a.position - b.position)
|
||||
.map(([, input], index) => {
|
||||
return {
|
||||
name: input.inputs[0],
|
||||
type: input.inputs[1],
|
||||
value: input.inputs.length > 2 ? input.inputs[2] : undefined,
|
||||
orderIndex: index // Ajouter un index d'ordre basé sur la position
|
||||
};
|
||||
});
|
||||
|
||||
// Séparer les inputs pour un traitement différencié
|
||||
const widget_inputs = mapped_input.filter(input => input.value !== undefined && input.value !== null);
|
||||
const pure_inputs = mapped_input.filter(input => input.value === undefined || input.value === null);
|
||||
|
||||
// S'assurer que le nœud a un objet local_input_defs
|
||||
if (!node.local_input_defs) {
|
||||
node.local_input_defs = {
|
||||
required: {},
|
||||
optional: {}
|
||||
};
|
||||
}
|
||||
|
||||
// Phase 2: Ajouter les nouveaux widgets/inputs avec leur index d'ordre
|
||||
for (const input of mapped_input) {
|
||||
const { name, type, value, orderIndex } = input;
|
||||
let isWidget = node.widgets.find(w => w.name === name);
|
||||
let isinput = node.inputs.find(i => i.name === name);
|
||||
|
||||
if (!isWidget && (!isinput||isinput.widget)){
|
||||
if (value.inputs[2]){
|
||||
const values = widgets_values[start_index] ?? value.inputs[2];
|
||||
const widget_param = {value: values, type: value.inputs[1]}
|
||||
//const widget_param = {value: widgets_values[start_index], type: value.inputs.default.type}
|
||||
addWidgets(root_obj, value.inputs[0], widget_param, app);
|
||||
if (isinput){
|
||||
//node.removeInput(node.inputs.findIndex((i) => i.widget?.name === widget.name))
|
||||
const config = [value.inputs[2]]
|
||||
convertToInput(root_obj, root_obj.widgets[start_index], config)
|
||||
if (!isWidget && (!isinput || isinput.widget)) {
|
||||
if (value !== undefined) {
|
||||
// Ajouter un widget avec sa valeur et son index d'ordre
|
||||
const widget_param = { value, type };
|
||||
addWidgets(node, name, widget_param, app);
|
||||
isWidget = node.widgets.find(w => w.name === name);
|
||||
isWidget.orderIndex = orderIndex; // Stocker l'index d'ordre
|
||||
|
||||
if (isinput && !isinput.widget) {
|
||||
convertToInput(node, isWidget);
|
||||
// Préserver l'index d'ordre sur l'input converti
|
||||
const newInput = node.inputs.find(i => i.name === name);
|
||||
if (newInput) newInput.orderIndex = orderIndex;
|
||||
newInput.pos = isWidget.pos;
|
||||
}
|
||||
} else {
|
||||
// C'est un input pur
|
||||
if (!isinput) {
|
||||
node.addInput(name, type);
|
||||
const newInput = node.inputs[node.inputs.length - 1];
|
||||
newInput.orderIndex = orderIndex; // Stocker l'index d'ordre
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Mettre à jour l'index d'ordre des éléments existants
|
||||
if (isWidget) isWidget.orderIndex = orderIndex;
|
||||
if (isinput) isinput.orderIndex = orderIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 3: Mettre à jour les types si nécessaires
|
||||
for (const input of mapped_input) {
|
||||
const { name, type, value } = input;
|
||||
let isWidget = node.widgets.find(w => w.name === name);
|
||||
let isinput = node.inputs.find(i => i.name === name);
|
||||
|
||||
if (isWidget || isinput) {
|
||||
const localType = node.local_input_defs?.required[name] || null;
|
||||
|
||||
// Vérifier si le type est différent et le mettre à jour
|
||||
if (localType && localType[0] !== type) {
|
||||
if (isinput) {
|
||||
if (isinput.link) {
|
||||
node.graph.removeLink(isinput.link);
|
||||
}
|
||||
isinput.type = type;
|
||||
}
|
||||
|
||||
if (isWidget) {
|
||||
isWidget.type = type;
|
||||
const options = getDefaultOptions(type, value);
|
||||
node.local_input_defs.required[name] = [type, options];
|
||||
isWidget.options = options;
|
||||
isWidget.value = value !== undefined ? value : isWidget.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 4: Réorganiser les widgets selon leur index d'ordre
|
||||
// Séparer les widgets système (les 2 premiers) des widgets à trier
|
||||
const systemWidgets = node.widgets.slice(0, 2);
|
||||
const sortableWidgets = node.widgets.slice(2);
|
||||
|
||||
// Trier les widgets par index d'ordre
|
||||
sortableWidgets.sort((a, b) => {
|
||||
if (a.orderIndex === undefined) return 1;
|
||||
if (b.orderIndex === undefined) return -1;
|
||||
return a.orderIndex - b.orderIndex;
|
||||
});
|
||||
|
||||
// Reconstruire le tableau des widgets
|
||||
node.widgets = [...systemWidgets, ...sortableWidgets];
|
||||
|
||||
// Maintenant ajuster les positions visuelles des widgets
|
||||
for (let i = 2; i < node.widgets.length; i++) {
|
||||
node.widgets[i].y = node.widgets[i-1].y + (node.widgets[i-1].computedHeight || LiteGraph.NODE_WIDGET_HEIGHT);
|
||||
node.widgets[i].last_y = node.widgets[i].y;
|
||||
}
|
||||
|
||||
// Réorganiser les inputs purs
|
||||
for (let i = 0; i < pure_inputs.length; i++) {
|
||||
const targetInput = pure_inputs[i];
|
||||
const actualIndex = node.inputs.findIndex(input => input.name === targetInput.name);
|
||||
|
||||
if (actualIndex !== -1) {
|
||||
// const actualIndex = node.inputs.indexOf(pureNodeInputs[inputIndex]);
|
||||
const expected_position = i;
|
||||
|
||||
if (actualIndex !== expected_position) {
|
||||
// Déconnecter temporairement le lien s'il existe
|
||||
let link = null;
|
||||
if (node.inputs[actualIndex].link) {
|
||||
link = node.graph.links[node.inputs[actualIndex].link];
|
||||
node.graph.removeLink(node.inputs[actualIndex].link);
|
||||
}
|
||||
|
||||
// Sauvegarder les propriétés importantes
|
||||
const inputToMove = node.inputs[actualIndex];
|
||||
const inputName = inputToMove.name;
|
||||
const inputType = inputToMove.type;
|
||||
const inputWidget = inputToMove.widget;
|
||||
const inputPos = inputToMove.pos;
|
||||
|
||||
// Supprimer l'input
|
||||
node.removeInput(actualIndex);
|
||||
|
||||
// Ajouter à la position attendue
|
||||
node.addInput(inputName, inputType, {pos: inputPos, widget: inputWidget}, expected_position);
|
||||
|
||||
// Reconnecter le lien si nécessaire
|
||||
if (link && link.origin_id !== null) {
|
||||
const newIndex = node.inputs.findIndex(input => input.name === targetInput.name);
|
||||
link.target_slot = newIndex;
|
||||
node.graph.links[link.id] = link;
|
||||
node.inputs[newIndex].link = link.id;
|
||||
}
|
||||
start_index += 1;
|
||||
}else{
|
||||
const input_param = {type: value.inputs[1]};
|
||||
addWidgets(root_obj, value.inputs[0], input_param, app);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 6: S'assurer que les inputs avec widget sont toujours à la fin de la liste
|
||||
const inputsWithWidgets = [];
|
||||
const inputsWithoutWidgets = [];
|
||||
|
||||
// 1. Trier les inputs en deux groupes
|
||||
for (let i = 0; i < node.inputs.length; i++) {
|
||||
if (node.inputs[i].widget) {
|
||||
inputsWithWidgets.push(i);
|
||||
} else {
|
||||
inputsWithoutWidgets.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Si des inputs avec widgets ne sont pas déjà à la fin, les réorganiser
|
||||
if (inputsWithWidgets.length > 0 && inputsWithWidgets[0] < inputsWithoutWidgets[inputsWithoutWidgets.length - 1]) {
|
||||
// Déplacer tous les inputs avec widgets à la fin
|
||||
for (let i = 0; i < inputsWithWidgets.length; i++) {
|
||||
const currentIndex = inputsWithWidgets[i] - i; // Ajuster l'index car la liste change à chaque suppression
|
||||
|
||||
// Sauvegarder les informations de l'input et son lien
|
||||
let link = null;
|
||||
if (node.inputs[currentIndex].link) {
|
||||
let link = null;
|
||||
if (node.inputs[actualIndex].link) {
|
||||
link = node.graph.links[node.inputs[actualIndex].link];
|
||||
node.graph.removeLink(node.inputs[actualIndex].link);
|
||||
}
|
||||
}
|
||||
|
||||
// Sauvegarder les propriétés importantes
|
||||
const inputToMove = node.inputs[currentIndex];
|
||||
const inputName = inputToMove.name;
|
||||
const inputType = inputToMove.type;
|
||||
const inputWidget = inputToMove.widget;
|
||||
const inputPos = inputToMove.pos;
|
||||
|
||||
node.removeInput(currentIndex);
|
||||
node.addInput(inputName, inputType, {pos: inputPos, widget: inputWidget});
|
||||
|
||||
// Reconnecter le lien si nécessaire
|
||||
if (link && link.origin_id !== null) {
|
||||
const newIndex = node.inputs.findIndex(input => input.name === inputName);
|
||||
if (node.graph)
|
||||
node.graph.links[link.id].target_slot = newIndex;
|
||||
node.inputs[expected_position].link = link.id;
|
||||
|
||||
}
|
||||
if (link && link.origin_id !== null) {
|
||||
const newIndex = node.inputs.findIndex(input => input.name === inputName);
|
||||
link.target_slot = newIndex;
|
||||
node.graph.links[link.id] = link;
|
||||
node.inputs[newIndex].link = link.id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Rafraîchir le canvas
|
||||
if (node.graph) {
|
||||
node.graph.setDirtyCanvas(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Rafraîchir le canvas si nécessaire
|
||||
if (node.graph) {
|
||||
node.graph.setDirtyCanvas(false, true);
|
||||
//node.graph.afterChange();
|
||||
node.graph.connectionChange(this);
|
||||
}
|
||||
}
|
||||
|
||||
export function organizeOutputs(node, workflow_name) {
|
||||
const outputs = app.lipsync_studio[workflow_name].outputs;
|
||||
|
||||
// Extraire et trier les outputs selon leur position
|
||||
const sortedOutputs = Object.entries(outputs)
|
||||
.sort(([, a], [, b]) => a.position - b.position)
|
||||
.map(([, output]) => ({
|
||||
name: output.inputs.Name.value,
|
||||
type: output.inputs.type.value
|
||||
}));
|
||||
|
||||
// Réorganiser les outputs selon l'ordre déterminé
|
||||
for (let i = 0; i < sortedOutputs.length; i++) {
|
||||
const targetOutput = sortedOutputs[i];
|
||||
const actualIndex = node.outputs.findIndex(output => output.name === targetOutput.name);
|
||||
|
||||
if (actualIndex !== -1 && actualIndex !== i) {
|
||||
// Sauvegarder les liens existants
|
||||
let links = [];
|
||||
if (node.outputs[actualIndex].links && node.outputs[actualIndex].links.length > 0) {
|
||||
for (const linkId of node.outputs[actualIndex].links) {
|
||||
const linkInfo = node.graph.links[linkId];
|
||||
if (linkInfo) {
|
||||
links.push({
|
||||
id: linkId,
|
||||
target_id: linkInfo.target_id,
|
||||
target_slot: linkInfo.target_slot
|
||||
});
|
||||
// Déconnecter temporairement
|
||||
node.graph.removeLink(linkId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sauvegarder les propriétés importantes
|
||||
const outputToMove = node.outputs[actualIndex];
|
||||
const outputName = outputToMove.name;
|
||||
const outputType = outputToMove.type;
|
||||
|
||||
// Supprimer l'output
|
||||
node.removeOutput(actualIndex);
|
||||
|
||||
// Ajouter à la position attendue
|
||||
node.addOutput(outputName, outputType, i);
|
||||
|
||||
// Reconnecter les liens sauvegardés
|
||||
for (const link of links) {
|
||||
node.graph.connect(node.id, i, link.target_id, link.target_slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rafraîchir le canvas
|
||||
if (node.graph) {
|
||||
node.graph.setDirtyCanvas(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function removeInputs(node, inputs, widgets_values){
|
||||
// Ensemble des noms d'entrées valides à partir de inputs
|
||||
const validInputNames = new Set();
|
||||
for (let [key, value] of Object.entries(inputs)) {
|
||||
if (value.inputs && value.inputs[0]) {
|
||||
validInputNames.add(value.inputs[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Noms à préserver quoi qu'il arrive
|
||||
const preserveNames = new Set(["workflows", "workflow"]);
|
||||
|
||||
// Collecter les noms d'entrées actuelles
|
||||
const currentInputNames = new Set();
|
||||
for (let input of node.inputs)
|
||||
if (!preserveNames.has(input.name))
|
||||
currentInputNames.add(input.name);
|
||||
|
||||
// Collecter les noms de widgets actuels (à partir de l'index 2)
|
||||
const currentWidgetNames = new Set();
|
||||
for (let i = 2; i < node.widgets.length; i++)
|
||||
if (!preserveNames.has(node.widgets[i].name))
|
||||
currentWidgetNames.add(node.widgets[i].name);
|
||||
|
||||
// Identifier les éléments à supprimer (ceux qui sont dans current mais pas dans valid)
|
||||
const inputsToRemove = [...currentInputNames].filter(name => !validInputNames.has(name));
|
||||
const widgetsToRemove = [...currentWidgetNames].filter(name => !validInputNames.has(name));
|
||||
|
||||
// Supprimer les entrées identifiées (en parcourant en sens inverse)
|
||||
if (inputsToRemove.length > 0)
|
||||
for (let i = node.inputs.length - 1; i >= 0; i--)
|
||||
if (inputsToRemove.includes(node.inputs[i].name)){
|
||||
// Déconnecter le lien s'il existe
|
||||
if (node.inputs[i].link != null)
|
||||
node.graph.removeLink(node.inputs[i].link);
|
||||
node.removeInput(i);
|
||||
}
|
||||
|
||||
// Supprimer les widgets identifiés (en parcourant en sens inverse)
|
||||
if (widgetsToRemove.length > 0)
|
||||
for (let i = node.widgets.length - 1; i >= 2; i--)
|
||||
if (widgetsToRemove.includes(node.widgets[i].name)) {
|
||||
widgetName = node.widgets[i].name;
|
||||
node.widgets.splice(i, 1);
|
||||
widgets_values.splice(i, 1);
|
||||
if (node.local_input_defs && node.local_input_defs.required[widgetName]){
|
||||
delete node.local_input_defs.required[widgetName];
|
||||
}
|
||||
// change y and last_y of widgets
|
||||
for (let j = i; j < node.widgets.length; j++){
|
||||
node.widgets[j].y -= node.widgets[j].computedHeight;
|
||||
node.widgets[j].last_y -= node.widgets[j].computedHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app.registerExtension({
|
||||
@@ -785,71 +987,37 @@ app.registerExtension({
|
||||
case "Workflow":
|
||||
nodeType.prototype.onNodeCreated = function() {
|
||||
chainCallback(this, "onConfigure", function(info) {
|
||||
//let widgetDict = info.widgets_values
|
||||
if (info.widgets_values[0] != "None"){
|
||||
//this.widgets[1].value = importWorkflow(this, info.widgets_values[0], app, nodeData)
|
||||
//if (this.widgets.length==2){
|
||||
const inputs = app.lipsync_studio[info.widgets_values[0]].inputs;
|
||||
addInputs(this, inputs, info.widgets_values);
|
||||
addOutputs(this, info.widgets_values[0]);
|
||||
importWorkflow(this, info.widgets_values[0], app, nodeData)
|
||||
.then(data => {
|
||||
if (data){
|
||||
this.widgets[1].value = data;
|
||||
const inputs = app.lipsync_studio[info.widgets_values[0]].inputs;
|
||||
addInputs(this, inputs, info.widgets_values);
|
||||
addOutputs(this, info.widgets_values[0]);
|
||||
//importWorkflow(this, info.widgets_values[0], app, nodeData)
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Erreur lors de l\'importation:', error);
|
||||
});
|
||||
|
||||
/*
|
||||
if (info.widgets_values[1] != this.widgets[1].value){
|
||||
this.widgets[1].value = info.widgets_values[1];
|
||||
}
|
||||
const inputs = app.lipsync_studio[info.widgets_values[0]].inputs;
|
||||
|
||||
let start_index = 2;
|
||||
for (let [key, value] of Object.entries(inputs)){
|
||||
const isinput = this.inputs.find(i => i.name == value.inputs.Name.value);
|
||||
const isWidget = this.widgets.find(w => w.name == value.inputs.Name.value);
|
||||
if (!isWidget && (!isinput||isinput.widget)){
|
||||
const widget_param = {value: info.widgets_values[start_index], type: value.inputs.default.type}
|
||||
addWidgets(this, value.inputs.Name.value, widget_param, app, nodeData);
|
||||
if (isinput){
|
||||
//node.removeInput(node.inputs.findIndex((i) => i.widget?.name === widget.name))
|
||||
const config = [value.inputs.default.type]
|
||||
convertToInput(this, this.widgets[start_index], config)
|
||||
}
|
||||
start_index += 1;
|
||||
const inputs = app.lipsync_studio[info.widgets_values[0]].inputs;
|
||||
|
||||
addInputs(this, inputs, info.widgets_values);
|
||||
addOutputs(this, info.widgets_values[0]);
|
||||
removeInputs(this, inputs, info.widgets_values);
|
||||
fitHeight(this);
|
||||
importWorkflow(this, info.widgets_values[0], app, nodeData)
|
||||
.then(data => {
|
||||
if (data){
|
||||
this.widgets[1].value = data;
|
||||
const inputs = app.lipsync_studio[info.widgets_values[0]].inputs;
|
||||
|
||||
addInputs(this, inputs, info.widgets_values);
|
||||
addOutputs(this, info.widgets_values[0]);
|
||||
removeInputs(this, inputs, info.widgets_values);
|
||||
fitHeight(this);
|
||||
//importWorkflow(this, info.widgets_values[0], app, nodeData)
|
||||
}
|
||||
}*/
|
||||
//}
|
||||
/*
|
||||
if(info.widgets_values[0] != "None")
|
||||
api.fetchApi("/flowchain/workflow?workflow_path="+info.widgets_values[0])
|
||||
.then(response => response.json())
|
||||
.then(async data => {
|
||||
cleanInputs(this);
|
||||
app.lipsync_studio[info.widgets_values[0]] = data;
|
||||
addInputs(this, info.widgets_values[0], info.widgets_values);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Erreur lors de l\'importation:', error);
|
||||
});*/
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Erreur lors de l\'importation:', error);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
chainCallback(this, "onSerialize", function(info) {
|
||||
for (let w of this.inputs){
|
||||
// if w.name exists in info.widgets_values
|
||||
|
||||
if (w.widget){
|
||||
if (w.type != this.local_input_defs.required[w.name][0])
|
||||
w.type = this.local_input_defs.required[w.name][0];
|
||||
for (let inp of this.inputs){
|
||||
if (inp.widget){
|
||||
if (inp.type != this.local_input_defs.required[inp.name][0])
|
||||
inp.type = this.local_input_defs.required[inp.name][0];
|
||||
}
|
||||
}
|
||||
if(this.widgets[0].options.values == "COMBO"){
|
||||
@@ -857,8 +1025,6 @@ app.registerExtension({
|
||||
}
|
||||
});
|
||||
const workflow_reload = this.title.startsWith("Workflow: ")?true:false;
|
||||
|
||||
// nodeData.input.required.workflows = ["COMBO", {values:["None", ...Object.keys(app.lipsync_studio)]}]
|
||||
this.widgets[0].options.values = ["None", ...Object.keys(app.lipsync_studio)]
|
||||
this.widgets[0].callback = ( value ) => {
|
||||
cleanInputs(this);
|
||||
@@ -867,8 +1033,9 @@ app.registerExtension({
|
||||
}else{
|
||||
this.widgets[1].value = importWorkflow(this, value, app, nodeData);
|
||||
const inputs = app.lipsync_studio[value].inputs;
|
||||
addInputs(this, inputs, {});
|
||||
addInputs(this, inputs, {}, true);
|
||||
addOutputs(this, value);
|
||||
fitHeight(this);
|
||||
}
|
||||
};
|
||||
if (!workflow_reload){
|
||||
@@ -890,99 +1057,9 @@ app.registerExtension({
|
||||
|
||||
inputs["default"] = {
|
||||
inputs: ["default", info.widgets_values[1], info.widgets_values[2]]
|
||||
/*
|
||||
default:{value: info.widgets_values[2], type: info.widgets_values[1]},
|
||||
Name: {value: "default", type: "STRING"},
|
||||
type: {value: info.widgets_values[1], type: "COMBO"}*/
|
||||
};
|
||||
|
||||
addInputs(this, inputs, info.widgets_values);
|
||||
/*
|
||||
const inputs = {};
|
||||
for (let [k, value] of Object.entries(info.widgets_values)) {
|
||||
if (k == "default"){
|
||||
inputs[k] = {
|
||||
inputs: {
|
||||
default:{value: value.value, type: info.widgets_values.default.type},
|
||||
Name: {value: k, type: "STRING"},
|
||||
type: {value: info.widgets_values.default.type, type: "STRING"}
|
||||
}
|
||||
};
|
||||
}else{
|
||||
inputs[k] = {
|
||||
inputs: {
|
||||
default:{value: value.value, type: value.type},
|
||||
Name: {value: k, type: value.type},
|
||||
type: {value: value.type, type: value.type}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
let widgetDict = {};
|
||||
if(info.widgets_values.default)
|
||||
widgetDict = [info.widgets_values.Name.value, info.widgets_values.default.type, info.widgets_values.default.value];
|
||||
else
|
||||
widgetDict = [info.widgets_values.Name.value, info.widgets_values.type.value];
|
||||
|
||||
addInputs(this, inputs, widgetDict);*/
|
||||
/*if (info.widgets_values.length == undefined) {
|
||||
|
||||
|
||||
for (let w of this.widgets) {
|
||||
if (w.name in widgetDict) {
|
||||
w.value = widgetDict[w.name].value;
|
||||
}
|
||||
}
|
||||
|
||||
// check if widgetDict in this.widgets
|
||||
for (let [key, value] of Object.entries(widgetDict)) {
|
||||
let widget = this.widgets.find(w => w.name === key);
|
||||
let type = this.widgets.find(w => w.name === "type");
|
||||
if(!widget){
|
||||
let widget_param = {}
|
||||
if (value.name == "default"){
|
||||
widget_param = {value: value.value, type: type.value}
|
||||
}else{
|
||||
widget_param = value;
|
||||
}
|
||||
// addWidgets(this, key, widget_param, app);
|
||||
addInputs(this, {inputs: {Name: {value: key}, type: {value: type.value}}}, widgetDict);
|
||||
widget = this.widgets.find(w => w.name === key);
|
||||
}
|
||||
//this.widgets.push(value);
|
||||
widget.options = info.widgets_values[key].options;
|
||||
widget.value = info.widgets_values[key].value;
|
||||
//if value exists in inputs
|
||||
|
||||
for (let input of this.inputs){
|
||||
if (input.name == key){
|
||||
//find if key exists in inputs array in inputs.Name
|
||||
if (info.widgets_values[key].type != "converted-widget"){
|
||||
this.removeInput(this.inputs.indexOf(input));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// get inputs by name
|
||||
|
||||
for (let w of this.inputs){
|
||||
if (w.name=="default"){
|
||||
w.type = info.widgets_values.type.value;
|
||||
}
|
||||
}
|
||||
if (info.outputs_values != undefined){
|
||||
// deep copy outputs
|
||||
if(this.id == -1){
|
||||
this.outputs[0] = {links: null, name: info.outputs_values.name, type: info.outputs_values.type};
|
||||
}else{
|
||||
this.outputs[0] = {...info.outputs_values};
|
||||
}
|
||||
}
|
||||
this.setSize(info.size);*/
|
||||
|
||||
});
|
||||
chainCallback(this, "onSerialize", function(info) {
|
||||
let widgetDict = info.widgets_values;
|
||||
@@ -998,68 +1075,9 @@ app.registerExtension({
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
info.widgets_values = {};
|
||||
if (!this.widgets) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let w of this.widgets) {
|
||||
if (w.name == "default"){
|
||||
const default_type = this.inputs.find(i => i.name == "default");
|
||||
if (default_type)
|
||||
info.widgets_values[w.name] = {name: w.name, options : w.options, value: w.value, type: default_type.type};
|
||||
else
|
||||
info.widgets_values[w.name] = {name: w.name, options : w.options, value: w.value, type: info.widgets_values.type.value};
|
||||
}else{
|
||||
info.widgets_values[w.name] = {name: w.name, options : w.options, value: w.value, type: w.type};
|
||||
}
|
||||
}*/
|
||||
/*
|
||||
for (let w of this.inputs){
|
||||
// if w.name exists in info.widgets_values
|
||||
if (info.widgets_values[w.name]){
|
||||
w.type = info.widgets_values[w.name].type;
|
||||
if(info.widgets_values[w.name].type == "converted-widget"){
|
||||
if(info.widgets_values[w.name].origType == "toggle"){
|
||||
w.type = "BOOLEAN";
|
||||
}else if(info.widgets_values[w.name].origType == "text"){
|
||||
w.type = "STRING";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// deep copy outputs without reference
|
||||
if (this.outputs.length > 0){
|
||||
if (this.outputs[0].links == null){
|
||||
info.outputs_values = {links: null, name: this.outputs[0].name, type: this.outputs[0].type};
|
||||
}else{
|
||||
info.outputs_values = {links: [...this.outputs[0].links], name: this.outputs[0].name, slot_index: this.outputs[0].slot_index, type: this.outputs[0].type};
|
||||
}
|
||||
}
|
||||
|
||||
this.setSize(info.size);*/
|
||||
});
|
||||
|
||||
this.widgets[1].callback = ( value ) => {
|
||||
// D'abord, déconnecter tous les liens existants
|
||||
/*for (let i = 0; i < this.outputs.length; i++) {
|
||||
const output = this.outputs[i];
|
||||
if (output.links && output.links.length) {
|
||||
const links = output.links.slice();
|
||||
for (const linkId of links) {
|
||||
this.graph.removeLink(linkId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.inputs.length; i++) {
|
||||
const input = this.inputs[i];
|
||||
if (input.link) {
|
||||
this.graph.removeLink(input.link);
|
||||
}
|
||||
}
|
||||
clearInputs(this);*/
|
||||
cleanInputs(this);
|
||||
|
||||
switch(value){
|
||||
|
||||
+1
-67
@@ -91,27 +91,7 @@ class Workflow(SaveImage):
|
||||
return m.digest().hex()
|
||||
|
||||
def generate(self, workflows, workflow, **kwargs):
|
||||
# get current file path
|
||||
"""
|
||||
def get_workflow(workflow_name):
|
||||
json_path = os.path.join(script_list_path, workflow_name)
|
||||
if os.path.exists(json_path):
|
||||
with open(json_path, "r", encoding="utf-8") as f:
|
||||
json_content = json.load(f)
|
||||
if "nodes" in json_content:
|
||||
try:
|
||||
api_workflow = convert_standard_to_api_format(json_content)
|
||||
if api_workflow:
|
||||
json_content = api_workflow
|
||||
else:
|
||||
print("Échec de la conversion du workflow standard en format API")
|
||||
except Exception as e:
|
||||
print(f"Erreur lors de la conversion: {str(e)}")
|
||||
else:
|
||||
print("File not found:",workflow_name)
|
||||
|
||||
return json_content
|
||||
"""
|
||||
def populate_inputs(workflow, inputs, kwargs_values):
|
||||
workflow_inputs = {k: v for k, v in workflow.items() if v["class_type"] == "WorkflowInput"}
|
||||
for key, value in workflow_inputs.items():
|
||||
@@ -345,44 +325,7 @@ class Workflow(SaveImage):
|
||||
# add subworkflow to workflow
|
||||
workflow.update(subworkflow)
|
||||
return workflow, max_id
|
||||
"""
|
||||
def format_output_value(value, type_name):
|
||||
if value is None:
|
||||
return None
|
||||
|
||||
if type_name == "STRING":
|
||||
# Convert list of characters or bytes to string
|
||||
if isinstance(value, list) and all(isinstance(x, (str, bytes)) for x in value):
|
||||
return ''.join(value)
|
||||
elif isinstance(value, (bytes, bytearray)):
|
||||
return value.decode('utf-8')
|
||||
|
||||
elif type_name == "INT":
|
||||
# Ensure integer conversion
|
||||
try:
|
||||
return int(value)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
elif type_name == "FLOAT":
|
||||
# Ensure float conversion
|
||||
try:
|
||||
return float(value)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
elif type_name == "BOOLEAN":
|
||||
# Convert to proper boolean
|
||||
if isinstance(value, (str, list)):
|
||||
if isinstance(value, str):
|
||||
return value.lower() in ('true', 'yes', '1', 't', 'y')
|
||||
elif len(value) > 0:
|
||||
return bool(value[0])
|
||||
return bool(value)
|
||||
|
||||
# For other types (LATENT, CLIP, MODEL, etc.), return as-is
|
||||
return value
|
||||
"""
|
||||
|
||||
server_instance = PromptServer.instance
|
||||
client_id = server_instance.client_id
|
||||
if server_instance and hasattr(server_instance, 'prompt_queue'):
|
||||
@@ -397,15 +340,6 @@ class Workflow(SaveImage):
|
||||
original_inputs = [v["inputs"] for k, v in queue_to_use[0][2].items() if
|
||||
"workflows" in v["inputs"] and v["inputs"]["workflows"] == workflows][0]
|
||||
|
||||
# find "workflow" node in queue_info["queue_pending"][-1][3]["extra_png_info"]["workflow"]["nodes"]
|
||||
"""
|
||||
for node in queue_to_use[-1][3]["extra_pnginfo"]["workflow"]["nodes"]:
|
||||
workflow_name = 'Workflow: ' + original_inputs["workflows"].replace(".json", "").replace("_", " ")
|
||||
if node["type"] == "Workflow" and node["title"] == workflow_name:
|
||||
workflow = node["widgets_values"][1]
|
||||
break
|
||||
"""
|
||||
|
||||
else:
|
||||
# Fallback to empty inputs if server instance not available
|
||||
original_inputs = {}
|
||||
|
||||
@@ -122,7 +122,6 @@ class WorkflowOutput:
|
||||
OUTPUT_NODE = True
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def IS_CHANGED(s, Name, type, ui=True, **kwargs):
|
||||
m = hashlib.sha256()
|
||||
@@ -158,33 +157,12 @@ class WorkflowOutput:
|
||||
NODE_CLASS_MAPPINGS_NODES = {
|
||||
"WorkflowInput": WorkflowInput,
|
||||
"WorkflowOutput": WorkflowOutput,
|
||||
|
||||
# "WorkflowInputImage": WorkflowInputImage,
|
||||
# "WorkflowInputString": WorkflowInputString,
|
||||
# "WorkflowInputBoolean": WorkflowInputBoolean,
|
||||
# "WorkflowInputInteger": WorkflowInputInteger,
|
||||
# "WorkflowInputFloat": WorkflowInputFloat,
|
||||
# "WorkflowOutputImage": WorkflowOutputImage,
|
||||
# "WorkflowInputSwitch": WorkflowInputSwitch,
|
||||
# "WorkflowContinueImage": WorkflowContinueImage,
|
||||
# "WorkflowContinueLatent": WorkflowContinueLatent,
|
||||
"WorkflowContinue": WorkflowContinue,
|
||||
|
||||
}
|
||||
|
||||
# A dictionary that contains the friendly/humanly readable titles for the nodes
|
||||
NODE_DISPLAY_NAME_MAPPINGS_NODES = {
|
||||
"WorkflowInput": "Workflow Input (FlowChain ⛓️)",
|
||||
"WorkflowOutput": "Workflow Output (FlowChain ⛓️)",
|
||||
# "WorkflowInputImage": "Workflow Input Image (Lipsync Studio)",
|
||||
# "WorkflowInputString": "Workflow Input String (Lipsync Studio)",
|
||||
# "WorkflowInputBoolean": "Workflow Input Boolean (Lipsync Studio)",
|
||||
# "WorkflowInputInteger": "Workflow Input Integer (Lipsync Studio)",
|
||||
# "WorkflowInputFloat": "Workflow Input Float (Lipsync Studio)",
|
||||
# "WorkflowOutputImage": "Workflow Output Image (Lipsync Studio)",
|
||||
# "WorkflowInputSwitch": "Workflow Input Switch (Lipsync Studio)",
|
||||
# "WorkflowContinueImage": "Workflow Continue Image (Lipsync Studio)",
|
||||
# "WorkflowContinueLatent": "Workflow Continue Latent (Lipsync Studio)",
|
||||
"WorkflowContinue": "Workflow Continue (FlowChain ⛓️)",
|
||||
# "VisualizeOpticalFlow": "Visualize optical flow",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user