Kar 2025-06-05 13:12:50 +00:00
parent c07ba54ed1
commit 127758a930
1 changed files with 76 additions and 74 deletions

View File

@ -1,7 +1,6 @@
const express = require('express'); const express = require('express');
const WebSocket = require('ws'); const WebSocket = require('ws');
const { spawn } = require('child_process'); const { spawn } = require('child_process');
const fs = require('fs');
const app = express(); const app = express();
const PORT = 3000; const PORT = 3000;
@ -17,16 +16,14 @@ const wss = new WebSocket.Server({ server });
class SpeechProcessor { class SpeechProcessor {
constructor() { constructor() {
this.pythonProcess = null; this.pythonProcess = null;
this.requestMap = new Map(); this.activeRequests = new Map();
this.requestCounter = 0; this.requestCounter = 0;
this.initializePythonProcess(); this.initializePythonProcess();
this.buffer = Buffer.alloc(0);
} }
initializePythonProcess() { initializePythonProcess() {
try { this.pythonProcess = spawn('python3', ['speech_processor.py']);
this.pythonProcess = spawn('python3', ['speech_processor.py'], {
stdio: ['pipe', 'pipe', 'pipe']
});
this.pythonProcess.stderr.on('data', (data) => { this.pythonProcess.stderr.on('data', (data) => {
console.error('Python STDERR:', data.toString()); console.error('Python STDERR:', data.toString());
@ -34,36 +31,30 @@ class SpeechProcessor {
this.pythonProcess.on('close', (code) => { this.pythonProcess.on('close', (code) => {
console.log(`Python process exited with code ${code}`); console.log(`Python process exited with code ${code}`);
this.requestMap.clear(); this.activeRequests.clear();
setTimeout(() => this.initializePythonProcess(), 1000); setTimeout(() => this.initializePythonProcess(), 1000);
}); });
let buffer = Buffer.alloc(0);
this.pythonProcess.stdout.on('data', (data) => { this.pythonProcess.stdout.on('data', (data) => {
buffer = Buffer.concat([buffer, data]); this.buffer = Buffer.concat([this.buffer, data]);
this.processBuffer(buffer); this.processBuffer();
}); });
console.log('Python processor initialized');
} catch (error) {
console.error('Failed to start Python:', error);
}
} }
processBuffer(buffer) { processBuffer() {
while (buffer.length >= 8) { while (this.buffer.length >= 8) {
const length = buffer.readUInt32BE(0); const length = this.buffer.readUInt32BE(0);
const requestId = buffer.readUInt32BE(4); const requestId = this.buffer.readUInt32BE(4);
if (buffer.length >= 8 + length) { if (this.buffer.length >= 8 + length) {
const message = buffer.slice(8, 8 + length); const message = this.buffer.slice(8, 8 + length);
buffer = buffer.slice(8 + length); this.buffer = this.buffer.slice(8 + length);
try { try {
const result = JSON.parse(message.toString()); const result = JSON.parse(message.toString());
if (this.requestMap.has(requestId)) { if (this.activeRequests.has(requestId)) {
const { resolve } = this.requestMap.get(requestId); const { resolve } = this.activeRequests.get(requestId);
this.requestMap.delete(requestId); this.activeRequests.delete(requestId);
resolve(result); resolve(result);
} }
} catch (error) { } catch (error) {
@ -73,7 +64,6 @@ class SpeechProcessor {
break; break;
} }
} }
return buffer;
} }
async processAudio(audioBuffer) { async processAudio(audioBuffer) {
@ -84,7 +74,7 @@ class SpeechProcessor {
} }
const requestId = this.requestCounter++; const requestId = this.requestCounter++;
this.requestMap.set(requestId, { resolve, reject }); this.activeRequests.set(requestId, { resolve, reject });
const lengthBuffer = Buffer.alloc(4); const lengthBuffer = Buffer.alloc(4);
lengthBuffer.writeUInt32BE(audioBuffer.length, 0); lengthBuffer.writeUInt32BE(audioBuffer.length, 0);
@ -97,8 +87,8 @@ class SpeechProcessor {
this.pythonProcess.stdin.write(audioBuffer); this.pythonProcess.stdin.write(audioBuffer);
setTimeout(() => { setTimeout(() => {
if (this.requestMap.has(requestId)) { if (this.activeRequests.has(requestId)) {
this.requestMap.delete(requestId); this.activeRequests.delete(requestId);
reject(new Error('Processing timeout')); reject(new Error('Processing timeout'));
} }
}, 5000); }, 5000);
@ -112,17 +102,22 @@ wss.on('connection', (ws) => {
console.log('Client connected'); console.log('Client connected');
let lastFinalText = ''; let lastFinalText = '';
let lastPartialUpdate = 0; let lastPartialText = '';
let partialText = ''; let partialTextTimeout = null;
ws.on('message', async (message) => { ws.on('message', async (message) => {
if (!Buffer.isBuffer(message)) return;
try { try {
if (Buffer.isBuffer(message)) {
const result = await speechProcessor.processAudio(message); const result = await speechProcessor.processAudio(message);
if (result.success) { if (!result.success) {
if (result.is_final) { console.error('Processing error:', result.error);
if (result.text && result.text !== lastFinalText) { return;
}
// Handle final results
if (result.is_final && result.text && result.text !== lastFinalText) {
lastFinalText = result.text; lastFinalText = result.text;
ws.send(JSON.stringify({ ws.send(JSON.stringify({
type: 'transcription', type: 'transcription',
@ -130,31 +125,38 @@ wss.on('connection', (ws) => {
is_final: true is_final: true
})); }));
console.log('Final:', result.text); console.log('Final:', result.text);
partialText = ''; lastPartialText = '';
if (partialTextTimeout) {
clearTimeout(partialTextTimeout);
partialTextTimeout = null;
} }
} else { }
// Only send partial updates every 300ms // Handle partial results with debouncing
const now = Date.now(); else if (!result.is_final && result.text && result.text !== lastPartialText) {
if (result.text && (now - lastPartialUpdate > 300 || !result.text.startsWith(partialText))) { lastPartialText = result.text;
partialText = result.text;
lastPartialUpdate = now; if (partialTextTimeout) {
clearTimeout(partialTextTimeout);
}
partialTextTimeout = setTimeout(() => {
ws.send(JSON.stringify({ ws.send(JSON.stringify({
type: 'partial_transcription', type: 'partial_transcription',
text: result.text, text: result.text,
is_final: false is_final: false
})); }));
} partialTextTimeout = null;
} }, 300); // 300ms debounce
} else {
console.error('Processing error:', result.error);
}
} }
} catch (error) { } catch (error) {
console.error('WebSocket error:', error); console.error('Processing error:', error);
} }
}); });
ws.on('close', () => { ws.on('close', () => {
console.log('Client disconnected'); console.log('Client disconnected');
if (partialTextTimeout) {
clearTimeout(partialTextTimeout);
}
}); });
}); });