UNPKG

n8n-nodes-comfyui

Version:

n8n node to integrate with ComfyUI stable diffusion workflows

221 lines 9.73 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Comfyui = void 0; const n8n_workflow_1 = require("n8n-workflow"); const jimp_1 = require("jimp"); class Comfyui { constructor() { this.description = { displayName: 'ComfyUI', name: 'comfyui', icon: 'file:comfyui.svg', group: ['transform'], version: 1, description: 'Execute ComfyUI workflows', defaults: { name: 'ComfyUI', }, credentials: [ { name: 'comfyUIApi', required: true, }, ], inputs: ['main'], outputs: ['main'], properties: [ { displayName: 'Workflow JSON', name: 'workflow', type: 'string', typeOptions: { rows: 10, }, default: '', required: true, description: 'The ComfyUI workflow in JSON format', }, { displayName: 'Output Format', name: 'outputFormat', type: 'options', options: [ { name: 'JPEG', value: 'jpeg', }, { name: 'PNG', value: 'png', }, ], default: 'jpeg', description: 'The format of the output images', }, { displayName: 'JPEG Quality', name: 'jpegQuality', type: 'number', typeOptions: { minValue: 1, maxValue: 100 }, default: 80, description: 'Quality of JPEG output (1-100)', displayOptions: { show: { outputFormat: ['jpeg'], }, }, }, { displayName: 'Timeout', name: 'timeout', type: 'number', default: 30, description: 'Maximum time in minutes to wait for workflow completion', }, ], }; } async execute() { var _a, _b; const credentials = await this.getCredentials('comfyUIApi'); const workflow = this.getNodeParameter('workflow', 0); const timeout = this.getNodeParameter('timeout', 0); const outputFormat = this.getNodeParameter('outputFormat', 0); let jpegQuality; if (outputFormat === 'jpeg') { jpegQuality = this.getNodeParameter('jpegQuality', 0); } const apiUrl = credentials.apiUrl; const apiKey = credentials.apiKey; console.log('[ComfyUI] Executing with API URL:', apiUrl); const headers = { 'Content-Type': 'application/json', }; if (apiKey) { console.log('[ComfyUI] Using API key authentication'); headers['Authorization'] = `Bearer ${apiKey}`; } try { console.log('[ComfyUI] Checking API connection...'); await this.helpers.request({ method: 'GET', url: `${apiUrl}/system_stats`, headers, json: true, }); console.log('[ComfyUI] Queueing prompt...'); const response = await this.helpers.request({ method: 'POST', url: `${apiUrl}/prompt`, headers, body: { prompt: JSON.parse(workflow), }, json: true, }); if (!response.prompt_id) { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: 'Failed to get prompt ID from ComfyUI' }); } const promptId = response.prompt_id; console.log('[ComfyUI] Prompt queued with ID:', promptId); let attempts = 0; const maxAttempts = 60 * timeout; await new Promise(resolve => setTimeout(resolve, 5000)); while (attempts < maxAttempts) { console.log(`[ComfyUI] Checking execution status (attempt ${attempts + 1}/${maxAttempts})...`); await new Promise(resolve => setTimeout(resolve, 1000)); attempts++; const history = await this.helpers.request({ method: 'GET', url: `${apiUrl}/history/${promptId}`, headers, json: true, }); const promptResult = history[promptId]; if (!promptResult) { console.log('[ComfyUI] Prompt not found in history'); continue; } if (promptResult.status === undefined) { console.log('[ComfyUI] Execution status not found'); continue; } if ((_a = promptResult.status) === null || _a === void 0 ? void 0 : _a.completed) { console.log('[ComfyUI] Execution completed'); if (((_b = promptResult.status) === null || _b === void 0 ? void 0 : _b.status_str) === 'error') { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: '[ComfyUI] Workflow execution failed' }); } if (!promptResult.outputs) { throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: '[ComfyUI] No outputs found in workflow result' }); } const outputs = await Promise.all(Object.values(promptResult.outputs) .flatMap((nodeOutput) => nodeOutput.images || []) .filter((image) => image.type === 'output' || image.type === 'temp') .map(async (file) => { console.log(`[ComfyUI] Downloading ${file.type} image:`, file.filename); let imageUrl = `${apiUrl}/view?filename=${file.filename}&subfolder=${file.subfolder || ''}&type=${file.type || ''}`; try { const imageData = await this.helpers.request({ method: 'GET', url: imageUrl, encoding: null, headers, }); const image = await jimp_1.Jimp.read(Buffer.from(imageData, 'base64')); let outputBuffer; if (outputFormat === 'jpeg') { outputBuffer = await image.getBuffer("image/jpeg", { quality: jpegQuality }); } else { outputBuffer = await image.getBuffer(`image/png`); } const outputBase64 = outputBuffer.toString('base64'); const item = { json: { filename: file.filename, type: file.type, subfolder: file.subfolder || '', data: outputBase64, }, binary: { data: { fileName: file.filename, data: outputBase64, fileType: 'image', fileSize: Math.round(outputBuffer.length / 1024 * 10) / 10 + " kB", fileExtension: outputFormat, mimeType: `image/${outputFormat}`, } } }; return item; } catch (error) { console.error(`[ComfyUI] Failed to download image ${file.filename}:`, error); return { json: { filename: file.filename, type: file.type, subfolder: file.subfolder || '', error: error.message, }, }; } })); console.log('[ComfyUI] All images downloaded successfully'); return [outputs]; } } throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: `Execution timeout after ${timeout} minutes` }); } catch (error) { console.error('[ComfyUI] Execution error:', error); throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: `ComfyUI API Error: ${error.message}` }); } } } exports.Comfyui = Comfyui; //# sourceMappingURL=Comfyui.node.js.map