UNPKG

n8n-nodes-elevenlabs-langfix

Version:

Complete implementation of ElevenLabs AI voice generation into n8n workflows.

420 lines 16.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SpeechOperations = void 0; exports.SpeechOperations = [ { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['speech'], }, }, options: [ { name: 'Text to Speech', value: 'text-to-speech', action: 'Generate speech from text', description: 'Generate a speech from a text', routing: { send: { preSend: [preSendText], }, }, }, { name: 'Speech to Speech', value: 'speech-to-speech', action: 'Generate speech from speech', description: 'Generate a speech from a speech', routing: { send: { preSend: [preSendUploadAudio], }, request: { headers: { 'Content-Type': 'multipart/form-data', }, }, output: { postReceive: [returnBinary], }, }, }, ], default: 'text-to-speech', routing: { request: { url: '={{"/text-to-speech/" + $parameter["voice_id"]}}', qs: { optimize_streaming_latency: '={{$parameter["additionalFields"]["optimize_streaming_latency"]}}', output_format: '={{$parameter["additionalFields"]["output_format"]}}', }, returnFullResponse: true, encoding: 'arraybuffer', }, output: { postReceive: [returnBinary], }, }, }, { displayName: 'Text', description: 'The Text to transform into Speech', required: true, name: 'text', type: 'string', default: 'Be good to people!', displayOptions: { show: { operation: ['text-to-speech'], }, }, }, { displayName: 'Voice Name or ID', name: 'voice_id', type: 'options', description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>', typeOptions: { loadOptionsMethod: 'listVoices', }, default: '', required: true, displayOptions: { show: { resource: ['speech'], }, }, }, { displayName: 'Model Name or ID', name: 'model_id', type: 'options', description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>', typeOptions: { loadOptionsMethod: 'listModels', }, default: '', required: true, displayOptions: { show: { resource: ['speech'], }, }, }, { displayName: 'Language Support Notice', name: 'languageNotice', type: 'notice', default: 'Language codes are only supported by the Turbo v2.5 model. Other models will return an error if a language code is provided.', displayOptions: { show: { resource: ['speech'], }, }, }, { displayName: 'Options', name: 'additionalFields', type: 'collection', placeholder: 'Add Option', default: {}, displayOptions: { show: { resource: ['speech'], }, }, options: [ { displayName: 'Binary Name', description: 'Name of the binary property to which to write the data', name: 'binary_name', type: 'string', default: 'data', }, { displayName: 'File Name', description: 'Name of the generated audio file', name: 'file_name', type: 'string', default: 'voice', }, { displayName: 'Output Format', description: 'Audio format of the generated speech', name: 'output_format', type: 'options', options: [ { name: 'FLAC (16kHz)', value: 'flac_16000', }, { name: 'FLAC (24kHz)', value: 'flac_24000', }, { name: 'MP3 (44.1KHz, 128kbps)', value: 'mp3_44100_128', }, { name: 'MP3 (44.1KHz, 64kbps)', value: 'mp3_44100_64', }, { name: 'MULAW (16kHz)', value: 'mulaw_16000', }, { name: 'WAVE (16kHz)', value: 'pcm_16000', }, { name: 'WAVE (24kHz)', value: 'pcm_24000', }, ], default: 'mp3_44100_128', }, { displayName: 'Voice Settings', name: 'voiceSettings', type: 'fixedCollection', default: {}, placeholder: 'Add Voice Setting', options: [ { name: 'values', displayName: 'Voice Settings', values: [ { displayName: 'Similarity Boost', description: 'How much the voice should match the original voice (0-1)', name: 'similarity_boost', type: 'number', default: 0.75, typeOptions: { maxValue: 1, minValue: 0, numberStepSize: 0.01, }, hint: '0 = more freedom, 1 = more similar', }, { displayName: 'Stability', description: 'How much the voice should vary across re-generations (0-1)', name: 'stability', type: 'number', default: 0.5, typeOptions: { maxValue: 1, minValue: 0, numberStepSize: 0.01, }, hint: '0 = more variable, 1 = more stable', }, { displayName: 'Style', description: 'Amount of style to apply to the voice (0-1)', name: 'style', type: 'number', default: 0, typeOptions: { maxValue: 1, minValue: 0, numberStepSize: 0.01, }, hint: '0 = neutral style, 1 = maximum style', }, { displayName: 'Speaker Boost', description: 'Whether to enhance voice clarity and target background noise', name: 'use_speaker_boost', type: 'boolean', default: true, }, ], }, ], }, { displayName: 'Streaming Latency', description: 'Optimize for streaming with lower latency but potentially reduced quality', name: 'optimize_streaming_latency', type: 'options', options: [ { name: 'Default (No Optimization)', value: 0, description: 'Best quality, highest latency', }, { name: 'Normal Optimization', value: 1, description: '~50% latency improvement', }, { name: 'Strong Optimization', value: 2, description: '~75% latency improvement', }, { name: 'Maximum Optimization', value: 3, description: 'Best possible latency', }, { name: 'Maximum + No Text Normalization', value: 4, description: 'Fastest but may mispronounce numbers/dates', }, ], default: 0, }, { displayName: 'Text Normalization', description: 'Controls how text is normalized before generation', name: 'apply_text_normalization', type: 'options', options: [ { name: 'Auto', value: 'auto', description: 'System decides whether to normalize text', }, { name: 'On', value: 'on', description: 'Always normalize text', }, { name: 'Off', value: 'off', description: 'Never normalize text', }, ], default: 'auto', hint: 'Cannot be turned on for Turbo v2.5 model', }, { displayName: 'Language Code', description: 'ISO 639-1 language code (e.g., en, de, fr)', name: 'language_code', type: 'string', default: '', placeholder: 'en', hint: 'Only works with Turbo v2.5 model', }, { displayName: 'Next Text', description: 'Text that comes after the current text', name: 'next_text', type: 'string', default: '', typeOptions: { rows: 2, }, hint: 'Helps improve prosody when concatenating generations', }, { displayName: 'Previous Text', description: 'Text that came before the current text', name: 'previous_text', type: 'string', default: '', typeOptions: { rows: 2, }, hint: 'Helps improve prosody when concatenating generations', }, { displayName: 'Seed', description: 'Fix the random seed for consistent results (0-4294967295)', name: 'seed', type: 'number', typeOptions: { maxValue: 4294967295, minValue: 0, }, default: 0, hint: 'Use the same seed to get the same voice output', }, ], }, ]; async function preSendUploadAudio(requestOptions) { const formData = new FormData(); const audioBuffer = await this.helpers.getBinaryDataBuffer('data'); formData.append('audio', new Blob([audioBuffer])); requestOptions.body = formData; return requestOptions; } async function preSendText(requestOptions) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s; const text = this.getNodeParameter('text'); const model_id = this.getNodeParameter('model_id'); const voice_id = this.getNodeParameter('voice_id'); let data = { text, model_id, voice_settings: {}, }; try { const voiceDetails = await this.helpers.httpRequestWithAuthentication.call(this, 'elevenLabsApi', { method: 'GET', url: `https://api.elevenlabs.io/v1/voices/${voice_id}`, qs: { with_settings: true, }, }); const voiceSettings = this.getNodeParameter('additionalFields.voiceSettings.values', {}); data.voice_settings = { stability: (_c = (_a = voiceSettings.stability) !== null && _a !== void 0 ? _a : (_b = voiceDetails.settings) === null || _b === void 0 ? void 0 : _b.stability) !== null && _c !== void 0 ? _c : 0.5, similarity_boost: (_f = (_d = voiceSettings.similarity_boost) !== null && _d !== void 0 ? _d : (_e = voiceDetails.settings) === null || _e === void 0 ? void 0 : _e.similarity_boost) !== null && _f !== void 0 ? _f : 0.75, style: (_j = (_g = voiceSettings.style) !== null && _g !== void 0 ? _g : (_h = voiceDetails.settings) === null || _h === void 0 ? void 0 : _h.style) !== null && _j !== void 0 ? _j : 0, use_speaker_boost: (_m = (_k = voiceSettings.use_speaker_boost) !== null && _k !== void 0 ? _k : (_l = voiceDetails.settings) === null || _l === void 0 ? void 0 : _l.use_speaker_boost) !== null && _m !== void 0 ? _m : true, }; if ((_o = voiceDetails.labels) === null || _o === void 0 ? void 0 : _o.language) { data.language_code = this.getNodeParameter('additionalFields.language_code', voiceDetails.labels.language); } } catch (error) { console.error('Failed to get voice details:', error); const voiceSettings = this.getNodeParameter('additionalFields.voiceSettings.values', {}); data.voice_settings = { stability: (_p = voiceSettings.stability) !== null && _p !== void 0 ? _p : 0.5, similarity_boost: (_q = voiceSettings.similarity_boost) !== null && _q !== void 0 ? _q : 0.75, style: (_r = voiceSettings.style) !== null && _r !== void 0 ? _r : 0, use_speaker_boost: (_s = voiceSettings.use_speaker_boost) !== null && _s !== void 0 ? _s : true, }; data.language_code = this.getNodeParameter('additionalFields.language_code', ''); } const textNormalization = this.getNodeParameter('additionalFields.apply_text_normalization', 'auto'); if (textNormalization !== 'auto') { data.apply_text_normalization = textNormalization; } const seed = this.getNodeParameter('additionalFields.seed', undefined); if (seed !== undefined) { data.seed = seed; } const previousText = this.getNodeParameter('additionalFields.previous_text', undefined); if (previousText) { data.previous_text = previousText; } const nextText = this.getNodeParameter('additionalFields.next_text', undefined); if (nextText) { data.next_text = nextText; } requestOptions.body = data; return requestOptions; } async function returnBinary(items, responseData) { const binary_name = this.getNodeParameter('additionalFields["binary_name"]', 'data'); const file_name = this.getNodeParameter('additionalFields["file_name"]', 'voice'); const binaryData = await this.helpers.prepareBinaryData(responseData.body, file_name, 'audio/mp3'); return items.map(() => ({ json: responseData.headers, binary: { [binary_name]: binaryData } })); } //# sourceMappingURL=speech.js.map