diff --git a/typescripts/comfyui/comfyui.tsx b/typescripts/comfyui/comfyui.tsx index c4e814f..34ae57d 100644 --- a/typescripts/comfyui/comfyui.tsx +++ b/typescripts/comfyui/comfyui.tsx @@ -94,7 +94,8 @@ export async function workflowEntries() { let entries = await workflow_folder.getEntries() const workflow_entries = entries.filter( - (e: any) => e.isFile && e.name.toLowerCase().includes('.png') // must be a file and has the of the type .png + // (e: any) => e.isFile && e.name.toLowerCase().includes('.png') // must be a file and has the of the type .png + (e: any) => e.isFile && e.name.toLowerCase().includes('.json') // must be a file and has the of the type .json ) console.log('workflow_entries: ', workflow_entries) @@ -102,6 +103,8 @@ export async function workflowEntries() { return workflow_entries } catch (e) { console.error(e) + // throw e + return [] } } export async function postPrompt(prompt: any) { @@ -1113,99 +1116,114 @@ function resetWorkflowData(workflow_name: string) { // resetNodeOrder() } function loadWorkflow2(workflow: any) { - //1) get prompt - store.data.current_prompt2 = copyJson(workflow) + try { + //1) get prompt + store.data.current_prompt2 = copyJson(workflow) - //2) get the original order - store.data.nodes_order = Object.keys(toJS(store.data.current_prompt2)) + //2) get the original order + store.data.nodes_order = Object.keys(toJS(store.data.current_prompt2)) - //3) get labels for each nodes - store.data.nodes_label = Object.fromEntries( - Object.entries(toJS(store.data.current_prompt2)).map( - ([node_id, node]: [string, any]) => { - return [ - node_id, - toJS(store.data.object_info[node.class_type]).display_name, - ] - } + //3) get labels for each nodes + store.data.nodes_label = Object.fromEntries( + Object.entries(toJS(store.data.current_prompt2)).map( + ([node_id, node]: [string, any]) => { + if (!(node.class_type in store.data.object_info)) { + throw new Error( + `ComfyUI Node of type "${node.class_type}" is not found. Please ensure it is installed via the ComfyUI Manager.` + ) + } + + return [ + node_id, + toJS(store.data.object_info[node.class_type]) + .display_name, + ] + } + ) + ) + store.data.is_random_seed = Object.fromEntries( + Object.keys(toJS(store.data.current_prompt2)).map( + (node_id: string) => { + return [node_id, false] + } + ) ) - ) - store.data.is_random_seed = Object.fromEntries( - Object.keys(toJS(store.data.current_prompt2)).map((node_id: string) => { - return [node_id, false] - }) - ) - // parse the output nodes - // Note: we can't modify the node directly in the prompt like we do for input nodes. - //.. since this data doesn't exist on the prompt. so we create separate container for the output images - store.data.current_prompt2_output = Object.entries( - store.data.current_prompt2 - ).reduce( - ( - output_entries: Record, - [node_id, node]: [string, any] - ) => { - if (store.data.object_info[node.class_type].output_node) { - output_entries[node_id] = [] - } - return output_entries - }, - {} - ) + // parse the output nodes + // Note: we can't modify the node directly in the prompt like we do for input nodes. + //.. since this data doesn't exist on the prompt. so we create separate container for the output images + store.data.current_prompt2_output = Object.entries( + store.data.current_prompt2 + ).reduce( + ( + output_entries: Record, + [node_id, node]: [string, any] + ) => { + if (store.data.object_info[node.class_type].output_node) { + output_entries[node_id] = [] + } + return output_entries + }, + {} + ) - //slider variables for output nodes - //TODO: delete store.data.output_thumbnail_image_size before loading a new workflow - for (let key in toJS(store.data.current_prompt2_output)) { - store.data.output_thumbnail_image_size[key] = 200 - } - - const workflow_name = store.data.selected_workflow_name - if (workflow_name) { - // check if the workflow has a name - - if (workflow_name in storage.localStorage) { - //load the workflow data from local storage - //1) load the last parameters used in generation - //2) load the order of the nodes - //3) load the labels of the nodes - - const workflow_data: WorkflowData = loadWorkflowData(workflow_name) - if ( - util.isSameStructure( - workflow_data.prompt, - toJS(store.data.current_prompt2) - ) - ) { - //load 1) - store.data.current_prompt2 = workflow_data.prompt - //load 2) - store.data.nodes_order = workflow_data.nodes_order - //load 3) - store.data.nodes_label = workflow_data.nodes_label - } else { - // do not load. instead override the localStorage with the new values - workflow_data.prompt = toJS(store.data.current_prompt2) - workflow_data.nodes_order = toJS(store.data.nodes_order) - workflow_data.nodes_label = toJS(store.data.nodes_label) - - saveWorkflowData(workflow_name, workflow_data) - } - } else { - // if workflow data is missing from local storage then save it for next time. - //1) save parameters values - //2) save nodes order - //3) save nodes label - - const prompt = toJS(store.data.current_prompt2) - const nodes_order = toJS(store.data.nodes_order) - const nodes_label = toJS(store.data.nodes_label) - saveWorkflowData(workflow_name, { - prompt, - nodes_order, - nodes_label, - }) + //slider variables for output nodes + //TODO: delete store.data.output_thumbnail_image_size before loading a new workflow + for (let key in toJS(store.data.current_prompt2_output)) { + store.data.output_thumbnail_image_size[key] = 200 } + + const workflow_name = store.data.selected_workflow_name + if (workflow_name) { + // check if the workflow has a name + + if (workflow_name in storage.localStorage) { + //load the workflow data from local storage + //1) load the last parameters used in generation + //2) load the order of the nodes + //3) load the labels of the nodes + + const workflow_data: WorkflowData = + loadWorkflowData(workflow_name) + if ( + util.isSameStructure( + workflow_data.prompt, + toJS(store.data.current_prompt2) + ) + ) { + //load 1) + store.data.current_prompt2 = workflow_data.prompt + //load 2) + store.data.nodes_order = workflow_data.nodes_order + //load 3) + store.data.nodes_label = workflow_data.nodes_label + } else { + // do not load. instead override the localStorage with the new values + workflow_data.prompt = toJS(store.data.current_prompt2) + workflow_data.nodes_order = toJS(store.data.nodes_order) + workflow_data.nodes_label = toJS(store.data.nodes_label) + + saveWorkflowData(workflow_name, workflow_data) + } + } else { + // if workflow data is missing from local storage then save it for next time. + //1) save parameters values + //2) save nodes order + //3) save nodes label + + const prompt = toJS(store.data.current_prompt2) + const nodes_order = toJS(store.data.nodes_order) + const nodes_label = toJS(store.data.nodes_label) + saveWorkflowData(workflow_name, { + prompt, + nodes_order, + nodes_label, + }) + } + } + } catch (e) { + console.error(e) + app.showAlert(`${e}`) } } @@ -1395,13 +1413,50 @@ class ComfyWorkflowComponent extends React.Component<{}, { value?: number }> { }} >{' '} + {store.data.object_info ? ( diff --git a/typescripts/comfyui/util.ts b/typescripts/comfyui/util.ts index 0a821fd..973d215 100644 --- a/typescripts/comfyui/util.ts +++ b/typescripts/comfyui/util.ts @@ -82,6 +82,7 @@ export const store = new AStore({ nodes_label: {} as Record, workflows2: workflows2 as Record, + user_custom_workflow: {} as Record, progress_value: 0, is_random_seed: {} as Record, last_moved: undefined as string | undefined, // the last node that has been moved in the edit mode @@ -241,6 +242,12 @@ export async function postPromptAndGetBase64JsonResult( const prompt_id = res.prompt_id const history = await getHistory(prompt_id) const promptInfo = history[prompt_id] + if (Object.keys(promptInfo.outputs).length === 0) { + throw new Error( + `No images were generated. Please check the ComfyUI console for potential errors.` + ) + } + const { outputs, separated_outputs } = await mapComfyOutputToStoreOutput( promptInfo.outputs,