UNPKG

n8n-nodes-groq

Version:

N8N community node for Groq API - Speech-to-Text transcription using Whisper AI. Convert audio to text with high accuracy. Perfect for WhatsApp voice messages, audio files, and voice automation workflows.

342 lines (341 loc) 14.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Groq = void 0; const n8n_workflow_1 = require("n8n-workflow"); const groq_sdk_1 = __importDefault(require("groq-sdk")); class Groq { constructor() { this.description = { displayName: 'Groq Speech to Text', name: 'groq', icon: 'file:groq-icon-logo-png_seeklogo-605779.png', group: ['transform'], version: 1, subtitle: '={{$parameter["operation"]}}', description: 'Interact with Groq API for AI operations', defaults: { name: 'Groq Speech to Text', }, inputs: ["main" /* NodeConnectionType.Main */], outputs: ["main" /* NodeConnectionType.Main */], credentials: [ { name: 'groqApi', required: true, }, ], properties: [ { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, options: [ { name: 'Speech to Text', value: 'speechToText', description: 'Convert audio to text using Whisper model', action: 'Convert speech to text', }, ], default: 'speechToText', }, { displayName: 'Audio Input', name: 'audioInput', type: 'options', displayOptions: { show: { operation: ['speechToText'], }, }, options: [ { name: 'Binary Data', value: 'binaryData', description: 'Use audio file from binary data', }, { name: 'URL', value: 'url', description: 'Download audio from URL', }, ], default: 'binaryData', }, { displayName: 'Binary Property', name: 'binaryPropertyName', type: 'string', default: 'data', required: true, displayOptions: { show: { operation: ['speechToText'], audioInput: ['binaryData'], }, }, description: 'Name of the binary property containing the audio file', }, { displayName: 'Audio URL', name: 'audioUrl', type: 'string', default: '', required: true, displayOptions: { show: { operation: ['speechToText'], audioInput: ['url'], }, }, description: 'URL of the audio file to transcribe', }, { displayName: 'Model', name: 'model', type: 'options', displayOptions: { show: { operation: ['speechToText'], }, }, options: [ { name: 'Whisper Large V3 Turbo', value: 'whisper-large-v3-turbo', description: 'Fastest and most efficient model', }, { name: 'Whisper Large V3', value: 'whisper-large-v3', description: 'High accuracy model', }, { name: 'Distil Whisper Large V3 EN', value: 'distil-whisper-large-v3-en', description: 'Optimized model for English audio', }, ], default: 'whisper-large-v3-turbo', description: 'The model to use for transcription', }, { displayName: 'Response Format', name: 'responseFormat', type: 'options', displayOptions: { show: { operation: ['speechToText'], }, }, options: [ { name: 'Text', value: 'text', description: 'Plain text output', }, { name: 'JSON', value: 'json', description: 'JSON format with metadata', }, { name: 'Verbose JSON', value: 'verbose_json', description: 'Detailed JSON with timestamps', }, ], default: 'text', description: 'Format of the transcription response', }, { displayName: 'Language', name: 'language', type: 'string', displayOptions: { show: { operation: ['speechToText'], }, }, default: '', placeholder: 'en', description: 'Language of the audio (ISO 639-1 code, e.g., "en" for English)', }, { displayName: 'Prompt (Optional)', name: 'prompt', type: 'string', displayOptions: { show: { operation: ['speechToText'], }, }, default: '', description: 'Texto opcional para guiar o estilo do modelo ou continuar um segmento de áudio anterior', }, { displayName: 'Temperature (Optional)', name: 'temperature', type: 'number', displayOptions: { show: { operation: ['speechToText'], }, }, default: 0, typeOptions: { minValue: 0, maxValue: 1, numberPrecision: 1, }, description: 'Sampling temperature between 0 and 1. Higher values make output more random.', }, { displayName: 'Timestamp Granularities', name: 'timestampGranularities', type: 'multiOptions', displayOptions: { show: { operation: ['speechToText'], responseFormat: ['verbose_json'], }, }, options: [ { name: 'Word', value: 'word', description: 'Word-level timestamps', }, { name: 'Segment', value: 'segment', description: 'Segment-level timestamps', }, ], default: ['segment'], description: 'Timestamp granularities to populate for this transcription', }, ], }; } async execute() { const items = this.getInputData(); const returnData = []; const credentials = await this.getCredentials('groqApi'); const groq = new groq_sdk_1.default({ apiKey: credentials.apiKey, }); for (let i = 0; i < items.length; i++) { let tempFilePath; try { const operation = this.getNodeParameter('operation', i); if (operation === 'speechToText') { const audioInput = this.getNodeParameter('audioInput', i); const model = this.getNodeParameter('model', i); const responseFormat = this.getNodeParameter('responseFormat', i); const language = this.getNodeParameter('language', i); const prompt = this.getNodeParameter('prompt', i); const temperature = this.getNodeParameter('temperature', i); let audioBuffer; let filename = 'audio.wav'; if (audioInput === 'binaryData') { const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i); const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName); audioBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); filename = binaryData.fileName || filename; } else { // URL input - download the file const audioUrl = this.getNodeParameter('audioUrl', i); const response = await this.helpers.httpRequest({ method: 'GET', url: audioUrl, encoding: 'arraybuffer', }); audioBuffer = Buffer.from(response); filename = audioUrl.split('/').pop() || filename; } // Create a File-like object that works with FormData const fs = require('fs'); const path = require('path'); const os = require('os'); // Create temporary file const tempDir = os.tmpdir(); tempFilePath = path.join(tempDir, `groq_audio_${Date.now()}_${filename}`); // Write buffer to temporary file fs.writeFileSync(tempFilePath, audioBuffer); // Create readable stream from file const audioFile = fs.createReadStream(tempFilePath); const transcriptionParams = { file: audioFile, model, response_format: responseFormat, }; if (language) transcriptionParams.language = language; if (prompt) transcriptionParams.prompt = prompt; if (temperature !== 0) transcriptionParams.temperature = temperature; if (responseFormat === 'verbose_json') { const timestampGranularities = this.getNodeParameter('timestampGranularities', i); if (timestampGranularities.length > 0) { transcriptionParams.timestamp_granularities = timestampGranularities; } } const transcription = await groq.audio.transcriptions.create(transcriptionParams); // Clean up temporary file try { fs.unlinkSync(tempFilePath); } catch (cleanupError) { // Ignore cleanup errors } returnData.push({ json: { transcription, model, responseFormat, filename, }, pairedItem: { item: i, }, }); } } catch (error) { // Clean up temporary file if it exists if (typeof tempFilePath !== 'undefined') { try { const fs = require('fs'); fs.unlinkSync(tempFilePath); } catch (cleanupError) { // Ignore cleanup errors } } if (this.continueOnFail()) { returnData.push({ json: { error: error.message, }, pairedItem: { item: i, }, }); continue; } throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex: i, }); } } return [returnData]; } } exports.Groq = Groq;