@thaleslaray/n8n-nodes-elevenlabs
Version:
Nó n8n para integração com a API da ElevenLabs incluindo Speech-to-Text, Text-to-Speech e Conversational AI
356 lines (355 loc) • 17.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ElevenLabsSpeechToText = void 0;
const n8n_workflow_1 = require("n8n-workflow");
const utils_1 = require("../utils");
class ElevenLabsSpeechToText {
constructor() {
this.description = {
displayName: 'ElevenLabs Speech-to-Text',
name: 'elevenLabsSpeechToText',
icon: 'file:../elevenlabs.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"]}}',
description: 'Converta áudio em texto usando a API da ElevenLabs',
defaults: {
name: 'ElevenLabs STT',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'elevenLabsApi',
required: true,
},
],
properties: [
{
displayName: 'Fonte do Áudio',
name: 'audioSource',
type: 'options',
options: [
{
name: 'Arquivo Binário',
value: 'binaryFile',
},
{
name: 'URL',
value: 'url',
},
],
default: 'binaryFile',
description: 'Fonte do arquivo de áudio para transcrição',
},
{
displayName: 'Campo Binário',
name: 'binaryPropertyName',
type: 'string',
default: 'data',
required: true,
displayOptions: {
show: {
audioSource: ['binaryFile'],
},
},
description: 'Nome do campo binário que contém o arquivo de áudio',
},
{
displayName: 'URL do Áudio',
name: 'audioUrl',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
audioSource: ['url'],
},
},
description: 'URL do arquivo de áudio para transcrição',
},
{
displayName: 'Modelo',
name: 'modelId',
type: 'options',
options: [
{
name: 'Scribe v1',
value: 'scribe_v1',
},
{
name: 'Scribe v1 Experimental',
value: 'scribe_v1_experimental',
},
],
default: 'scribe_v1',
description: 'O ID do modelo a ser usado para transcrição, atualmente apenas "scribe_v1" e "scribe_v1_experimental" estão disponíveis',
},
{
displayName: 'Opções Avançadas',
name: 'advancedOptions',
type: 'collection',
placeholder: 'Adicionar Opção',
default: {},
options: [
{
displayName: 'Código de Idioma',
name: 'languageCode',
type: 'string',
default: '',
placeholder: 'pt, en, es, fr...',
description: 'Código ISO-639-1 ou ISO-639-3 do idioma do áudio. Se não especificado, o idioma será detectado automaticamente.',
},
{
displayName: 'Diarização',
name: 'diarization',
type: 'boolean',
default: false,
description: 'Identificar diferentes falantes no áudio',
},
{
displayName: 'Timestamps',
name: 'timestampsGranularity',
type: 'options',
options: [
{
name: 'Nenhum',
value: 'none',
},
{
name: 'Palavra',
value: 'word',
},
{
name: 'Caractere',
value: 'character',
},
],
default: 'word',
description: 'Granularidade dos timestamps no texto transcrito',
},
{
displayName: 'Marcar Eventos de Áudio',
name: 'tagAudioEvents',
type: 'boolean',
default: true,
description: 'Marcar eventos de áudio como (risos), (passos), etc.',
},
{
displayName: 'Número Máximo de Falantes',
name: 'numSpeakers',
type: 'number',
typeOptions: {
minValue: 1,
maxValue: 32,
},
default: 1,
description: 'Número máximo de falantes no áudio (1-32)',
},
{
displayName: 'Formato de Arquivo',
name: 'fileFormat',
type: 'options',
options: [
{
name: 'Outro',
value: 'other',
},
{
name: 'PCM 16-bit 16kHz',
value: 'pcm_s16le_16',
}
],
default: 'other',
description: 'O formato do áudio de entrada',
},
{
displayName: 'Formatos Adicionais',
name: 'additionalFormats',
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
},
default: {},
options: [
{
displayName: 'Formato',
name: 'format',
values: [
{
displayName: 'Tipo',
name: 'format',
type: 'options',
options: [
{
name: 'DOCX',
value: 'docx',
},
{
name: 'HTML',
value: 'html',
},
{
name: 'PDF',
value: 'pdf',
},
{
name: 'JSON Segmentado',
value: 'segmented_json',
},
{
name: 'SRT',
value: 'srt',
},
{
name: 'TXT',
value: 'txt',
},
],
default: 'txt',
description: 'Formato adicional para exportar a transcrição',
},
{
displayName: 'Incluir Falantes',
name: 'include_speakers',
type: 'boolean',
default: false,
description: 'Incluir identificação dos falantes no formato adicional',
},
{
displayName: 'Incluir Timestamps',
name: 'include_timestamps',
type: 'boolean',
default: true,
description: 'Incluir marcações de tempo no formato adicional',
},
{
displayName: 'Máximo de Caracteres por Linha',
name: 'max_characters_per_line',
type: 'number',
default: 0,
description: 'Número máximo de caracteres por linha (0 para sem limite)',
},
{
displayName: 'Máximo de Caracteres por Segmento',
name: 'max_segment_chars',
type: 'number',
default: 0,
description: 'Número máximo de caracteres por segmento (0 para sem limite)',
},
{
displayName: 'Duração Máxima do Segmento (s)',
name: 'max_segment_duration_s',
type: 'number',
default: 0,
description: 'Duração máxima de cada segmento em segundos (0 para sem limite)',
},
{
displayName: 'Segmentar em Silêncios Maiores que (s)',
name: 'segment_on_silence_longer_than_s',
type: 'number',
default: 0,
description: 'Criar novo segmento quando encontrar silêncio maior que X segundos (0 para desabilitar)',
},
],
},
],
},
],
},
],
};
}
async execute() {
var _a;
const items = this.getInputData();
const returnData = [];
for (let i = 0; i < items.length; i++) {
try {
const audioSource = this.getNodeParameter('audioSource', i);
const model = this.getNodeParameter('modelId', i);
const advancedOptions = this.getNodeParameter('advancedOptions', i);
const formData = {
model_id: model,
};
if (advancedOptions.languageCode) {
formData.language_code = advancedOptions.languageCode;
}
if (advancedOptions.diarization !== undefined) {
formData.diarize = advancedOptions.diarization.toString();
}
if (advancedOptions.timestampsGranularity !== undefined) {
formData.timestamps_granularity = advancedOptions.timestampsGranularity;
}
if (advancedOptions.tagAudioEvents !== undefined) {
formData.tag_audio_events = advancedOptions.tagAudioEvents.toString();
}
if (advancedOptions.numSpeakers !== undefined) {
formData.num_speakers = advancedOptions.numSpeakers.toString();
}
if (advancedOptions.fileFormat !== undefined) {
formData.file_format = advancedOptions.fileFormat;
}
if (advancedOptions.additionalFormats) {
const formats = [];
for (const format of advancedOptions.additionalFormats.format) {
formats.push({
format: format.format,
include_speakers: format.include_speakers,
include_timestamps: format.include_timestamps,
max_characters_per_line: format.max_characters_per_line,
max_segment_chars: format.max_segment_chars,
max_segment_duration_s: format.max_segment_duration_s,
segment_on_silence_longer_than_s: format.segment_on_silence_longer_than_s,
});
}
if (formats.length > 0) {
formData.additional_formats = JSON.stringify(formats);
}
}
const options = await utils_1.createBaseOptions.call(this, 'speech-to-text', 'POST');
const finalFormData = {};
for (const [key, value] of Object.entries(formData)) {
if (typeof value === 'boolean') {
finalFormData[key] = value.toString();
}
else {
finalFormData[key] = value;
}
}
if (audioSource === 'binaryFile') {
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i);
const binaryData = (_a = items[i].binary) === null || _a === void 0 ? void 0 : _a[binaryPropertyName];
if (!binaryData) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Nenhum dado binário encontrado');
}
const buffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
finalFormData.file = {
value: buffer,
options: {
filename: binaryData.fileName || 'audio.mp3',
contentType: binaryData.mimeType,
},
};
}
else {
const audioUrl = this.getNodeParameter('audioUrl', i);
finalFormData.cloud_storage_url = audioUrl;
}
options.formData = finalFormData;
const response = await this.helpers.request(options);
returnData.push((0, utils_1.formatReturnData)(response, i));
}
catch (error) {
const errorResult = utils_1.handleApiError.call(this, error, i);
if (errorResult) {
returnData.push(errorResult);
continue;
}
throw error;
}
}
return [returnData];
}
}
exports.ElevenLabsSpeechToText = ElevenLabsSpeechToText;