n8n-nodes-comfyui-text-to-audio
Version:
n8n node to integrate with ComfyUI stable diffusion workflows for text to audio conversion
350 lines • 19.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ComfyuiTextToAudio = void 0;
const n8n_workflow_1 = require("n8n-workflow");
class ComfyuiTextToAudio {
constructor() {
this.description = {
displayName: 'ComfyUI Text to Audio',
name: 'comfyuiTextToAudio',
icon: 'file:comfyui.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["text"]}}',
description: 'Generate audio from text using ComfyUI workflows',
defaults: {
name: 'ComfyUI Text to Audio',
},
inputs: ["main"],
outputs: ["main"],
credentials: [
{
name: 'comfyUIApi',
required: false,
},
],
properties: [
{
displayName: 'Workflow JSON',
name: 'workflowJson',
type: 'json',
default: '{}',
required: true,
description: 'ComfyUI workflow JSON for text-to-audio generation',
typeOptions: {
rows: 10,
},
},
{
displayName: 'Text',
name: 'text',
type: 'string',
default: '',
required: true,
description: 'Text to convert to audio',
typeOptions: {
rows: 3,
},
},
{
displayName: 'Timeout (Minutes)',
name: 'timeout',
type: 'number',
default: 5,
required: true,
description: 'Maximum time in minutes to wait for audio generation',
typeOptions: {
minValue: 1,
maxValue: 60,
},
},
],
};
}
async execute() {
var _a, _b, _c;
const items = this.getInputData();
const returnData = [];
for (let i = 0; i < items.length; i++) {
try {
const workflowJson = this.getNodeParameter('workflowJson', i);
const inputText = this.getNodeParameter('text', i);
const timeout = this.getNodeParameter('timeout', i);
if (!inputText) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Text input is required', {
itemIndex: i,
});
}
let workflow;
try {
workflow = typeof workflowJson === 'string' ? JSON.parse(workflowJson) : workflowJson;
}
catch (error) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid workflow JSON', {
itemIndex: i,
});
}
const credentials = await this.getCredentials('comfyUIApi');
const apiUrl = (credentials === null || credentials === void 0 ? void 0 : credentials.apiUrl) || 'http://127.0.0.1:8188';
const apiKey = credentials === null || credentials === void 0 ? void 0 : credentials.apiKey;
for (const nodeId in workflow) {
const node = workflow[nodeId];
if (node && node.inputs) {
if (node.inputs.text !== undefined) {
node.inputs.text = inputText;
}
if (node.inputs.prompt !== undefined) {
node.inputs.prompt = inputText;
}
if (node.inputs.string !== undefined) {
node.inputs.string = inputText;
}
}
}
const headers = {
'Content-Type': 'application/json',
};
if (apiKey) {
headers['Authorization'] = `Bearer ${apiKey}`;
}
const promptResponse = await this.helpers.request({
method: 'POST',
url: `${apiUrl}/prompt`,
headers,
body: {
prompt: workflow,
},
json: true,
});
if (!promptResponse.prompt_id) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Failed to queue ComfyUI prompt');
}
const promptId = promptResponse.prompt_id;
const timeoutMs = timeout * 60 * 1000;
const startTime = Date.now();
while (Date.now() - startTime < timeoutMs) {
try {
const historyResponse = await this.helpers.request({
method: 'GET',
url: `${apiUrl}/history/${promptId}`,
headers: apiKey ? { 'Authorization': `Bearer ${apiKey}` } : {},
json: true,
});
if (historyResponse[promptId]) {
const history = historyResponse[promptId];
if (history.status && history.status.completed) {
const outputs = history.outputs || {};
let audioFound = false;
for (const nodeId in outputs) {
const nodeOutput = outputs[nodeId];
if (nodeOutput.files && nodeOutput.files.length > 0) {
for (const file of nodeOutput.files) {
const filename = file.filename || file;
if (typeof filename === 'string' &&
(filename.endsWith('.wav') || filename.endsWith('.mp3') ||
filename.endsWith('.ogg') || filename.endsWith('.flac') ||
filename.endsWith('.aac') || filename.endsWith('.m4a'))) {
try {
const downloadUrl = `${apiUrl}/view?filename=${encodeURIComponent(filename)}&type=output`;
const downloadHeaders = {};
if (apiKey) {
downloadHeaders['Authorization'] = `Bearer ${apiKey}`;
}
const audioBuffer = await this.helpers.request({
method: 'GET',
url: downloadUrl,
headers: downloadHeaders,
encoding: null,
});
const audioData = Buffer.from(audioBuffer).toString('base64');
const originalExtension = ((_a = filename.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || 'wav';
const mimeTypes = {
'wav': 'audio/wav',
'mp3': 'audio/mpeg',
'ogg': 'audio/ogg',
'flac': 'audio/flac',
'aac': 'audio/aac',
'm4a': 'audio/mp4',
};
const mimeType = mimeTypes[originalExtension] || 'audio/wav';
const binaryData = {
data: audioData,
mimeType: mimeType,
fileName: filename,
fileExtension: originalExtension,
};
returnData.push({
json: {
success: true,
fileName: filename,
fileExtension: originalExtension,
mimeType: mimeType,
text: inputText,
downloadUrl: downloadUrl,
},
binary: {
data: binaryData,
},
});
audioFound = true;
}
catch (error) {
continue;
}
}
}
if (audioFound)
break;
}
if (!audioFound && nodeOutput.audio && nodeOutput.audio.length > 0) {
const audioFile = nodeOutput.audio[0];
const originalFilename = audioFile.filename;
const downloadUrl = `${apiUrl}/view?filename=${encodeURIComponent(originalFilename)}&type=output`;
const downloadHeaders = {};
if (apiKey) {
downloadHeaders['Authorization'] = `Bearer ${apiKey}`;
}
const audioBuffer = await this.helpers.request({
method: 'GET',
url: downloadUrl,
headers: downloadHeaders,
encoding: null,
});
const audioData = Buffer.from(audioBuffer).toString('base64');
const originalExtension = ((_b = originalFilename.split('.').pop()) === null || _b === void 0 ? void 0 : _b.toLowerCase()) || 'wav';
const mimeTypes = {
'wav': 'audio/wav',
'mp3': 'audio/mpeg',
'ogg': 'audio/ogg',
'flac': 'audio/flac',
'aac': 'audio/aac',
'm4a': 'audio/mp4',
};
const mimeType = mimeTypes[originalExtension] || 'audio/wav';
const binaryData = {
data: audioData,
mimeType: mimeType,
fileName: originalFilename,
fileExtension: originalExtension,
};
returnData.push({
json: {
success: true,
fileName: originalFilename,
fileExtension: originalExtension,
mimeType: mimeType,
text: inputText,
downloadUrl: downloadUrl,
},
binary: {
data: binaryData,
},
});
audioFound = true;
break;
}
if (!audioFound && nodeOutput.outputs && nodeOutput.outputs.audio) {
const audioOutput = nodeOutput.outputs.audio;
if (audioOutput && audioOutput.length > 0) {
const audioFile = audioOutput[0];
const originalFilename = audioFile.filename;
const downloadUrl = `${apiUrl}/view?filename=${encodeURIComponent(originalFilename)}&type=output`;
const downloadHeaders = {};
if (apiKey) {
downloadHeaders['Authorization'] = `Bearer ${apiKey}`;
}
const audioBuffer = await this.helpers.request({
method: 'GET',
url: downloadUrl,
headers: downloadHeaders,
encoding: null,
});
const audioData = Buffer.from(audioBuffer).toString('base64');
const originalExtension = ((_c = originalFilename.split('.').pop()) === null || _c === void 0 ? void 0 : _c.toLowerCase()) || 'wav';
const mimeTypes = {
'wav': 'audio/wav',
'mp3': 'audio/mpeg',
'ogg': 'audio/ogg',
'flac': 'audio/flac',
'aac': 'audio/aac',
'm4a': 'audio/mp4',
};
const mimeType = mimeTypes[originalExtension] || 'audio/wav';
const binaryData = {
data: audioData,
mimeType: mimeType,
fileName: originalFilename,
fileExtension: originalExtension,
};
returnData.push({
json: {
success: true,
fileName: originalFilename,
fileExtension: originalExtension,
mimeType: mimeType,
text: inputText,
downloadUrl: downloadUrl,
},
binary: {
data: binaryData,
},
});
audioFound = true;
break;
}
}
}
if (!audioFound) {
returnData.push({
json: {
success: true,
message: 'ComfyUI workflow completed successfully - no audio output found',
text: inputText,
outputs: outputs,
debug: {
outputKeys: Object.keys(outputs),
outputStructure: JSON.stringify(outputs, null, 2),
},
},
});
}
break;
}
if (history.status && history.status.status_str === 'error') {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `ComfyUI execution failed: ${JSON.stringify(history.status)}`);
}
}
await new Promise(resolve => setTimeout(resolve, 2000));
}
catch (error) {
if (error instanceof n8n_workflow_1.NodeOperationError) {
throw error;
}
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
if (returnData.length === 0) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `ComfyUI execution timed out after ${timeout} minutes`);
}
}
catch (error) {
if (this.continueOnFail()) {
returnData.push({
json: {
error: error.message,
success: false,
},
pairedItem: {
item: i,
},
});
continue;
}
throw error;
}
}
return [returnData];
}
}
exports.ComfyuiTextToAudio = ComfyuiTextToAudio;
//# sourceMappingURL=ComfyuiTextToAudio.node.js.map