n8n-nodes-assemblyai-stream
Version:
n8n node for streaming audio to AssemblyAI using node-microphone
144 lines • 5.89 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AssemblyAIStream = void 0;
const n8n_workflow_1 = require("n8n-workflow");
const ws_1 = __importDefault(require("ws"));
const node_microphone_1 = __importDefault(require("node-microphone"));
class AssemblyAIStream {
constructor() {
this.description = {
displayName: 'AssemblyAI Stream',
name: 'assemblyAIStream',
group: ['transform'],
version: 1,
description: 'Stream microphone audio to AssemblyAI for real-time transcription',
defaults: {
name: 'AssemblyAI Stream',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'assemblyAIApi',
required: true,
},
],
properties: [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Start Streaming',
value: 'startStreaming',
description: 'Start streaming audio from microphone',
action: 'Start streaming audio from microphone',
},
],
default: 'startStreaming',
},
{
displayName: 'Duration (seconds)',
name: 'duration',
type: 'number',
default: 30,
description: 'Duration to record in seconds (0 for continuous)',
},
{
displayName: 'Device',
name: 'device',
type: 'string',
default: 'default',
description: 'Microphone device to use (leave as default for system default)',
},
],
};
}
async execute() {
const operation = this.getNodeParameter('operation', 0);
const duration = this.getNodeParameter('duration', 0);
const device = this.getNodeParameter('device', 0);
const credentials = await this.getCredentials('assemblyAIApi');
if (!credentials) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'No credentials provided!');
}
const apiKey = credentials.apiKey;
if (operation === 'startStreaming') {
const response = await fetch('https://api.assemblyai.com/v2/realtime/token', {
method: 'POST',
headers: {
'Authorization': apiKey,
},
});
if (!response.ok) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Failed to get AssemblyAI token');
}
const { token } = await response.json();
const ws = new ws_1.default(`wss://api.assemblyai.com/v2/realtime/ws?token=${token}`, {
headers: {
'Authorization': apiKey,
},
});
return new Promise((resolve, reject) => {
const results = [];
const mic = new node_microphone_1.default({
device: device === 'default' ? undefined : device,
rate: 16000,
channels: 1,
debug: false,
});
let micStream = null;
const handleMicError = (error) => {
ws.close();
reject(new n8n_workflow_1.NodeOperationError(this.getNode(), `Microphone error: ${error.message}`));
};
ws.on('open', () => {
console.log('WebSocket connection established');
micStream = mic.startRecording();
micStream.on('error', handleMicError);
micStream.on('data', (data) => {
if (ws.readyState === ws_1.default.OPEN) {
ws.send(JSON.stringify({
audio_data: data.toString('base64'),
}));
}
});
if (duration > 0) {
setTimeout(() => {
mic.stopRecording();
ws.close();
}, duration * 1000);
}
});
ws.on('message', (message) => {
const data = JSON.parse(message.toString());
if (data.message_type === 'FinalTranscript') {
results.push({
json: {
text: data.text,
timestamp: new Date().toISOString(),
confidence: data.confidence,
},
});
}
});
ws.on('error', (error) => {
mic.stopRecording();
reject(new n8n_workflow_1.NodeOperationError(this.getNode(), `WebSocket error: ${error.message}`));
});
ws.on('close', () => {
mic.stopRecording();
resolve([results]);
});
});
}
return [[]];
}
}
exports.AssemblyAIStream = AssemblyAIStream;
//# sourceMappingURL=AssemblyAIStream.node.js.map