class STTWebSocketClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.ws = null;
this.ready = false;
this.audioContext = null;
this.processor = null;
}
async connect() {
return new Promise((resolve, reject) => {
this.ws = new WebSocket('wss://api.voxnexus.ai/v1/stt/realtime', {
headers: {
'Authorization': `Bearer ${this.apiKey}`
}
});
this.ws.onopen = () => {
console.log('Connected');
resolve();
};
this.ws.onmessage = (event) => {
this.handleMessage(JSON.parse(event.data));
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
reject(error);
};
this.ws.onclose = () => {
console.log('Connection closed');
this.ready = false;
};
});
}
initialize(config) {
this.ws.send(JSON.stringify({
type: 'init',
...config
}));
}
async startRecording(sampleRate = 16000) {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
this.audioContext = new AudioContext({ sampleRate });
const source = this.audioContext.createMediaStreamSource(stream);
this.processor = this.audioContext.createScriptProcessor(4096, 1, 1);
this.processor.onaudioprocess = (e) => {
if (!this.ready) return;
const audioData = e.inputBuffer.getChannelData(0);
const pcm16 = new Int16Array(audioData.length);
for (let i = 0; i < audioData.length; i++) {
pcm16[i] = Math.max(-32768, Math.min(32767, audioData[i] * 32768));
}
const base64 = btoa(String.fromCharCode(...new Uint8Array(pcm16.buffer)));
this.ws.send(JSON.stringify({
type: 'audio',
data: base64
}));
};
source.connect(this.processor);
this.processor.connect(this.audioContext.destination);
}
stopRecording() {
if (this.processor) {
this.processor.disconnect();
this.processor = null;
}
if (this.audioContext) {
this.audioContext.close();
this.audioContext = null;
}
}
handleMessage(message) {
switch (message.type) {
case 'ready':
this.ready = true;
console.log('Ready:', message.request_id);
break;
case 'partial':
this.onPartial(message.text);
break;
case 'final':
this.onFinal(message);
break;
case 'error':
console.error('Error:', message.error);
this.onError(message);
break;
}
}
onPartial(text) {
console.log('Partial:', text);
// Update UI with interim results
}
onFinal(result) {
console.log('Final:', result.text);
console.log('Confidence:', result.confidence);
// Handle final transcription
}
onError(error) {
// Handle error
}
close() {
this.stopRecording();
if (this.ws) {
this.ws.close();
}
}
}
// Usage
const client = new STTWebSocketClient('YOUR_API_KEY');
await client.connect();
client.initialize({
format: 'pcm',
sample_rate: 16000,
enable_timestamps: true,
enable_confidence: true
});
// Wait for ready, then start recording
setTimeout(async () => {
await client.startRecording(16000);
}, 1000);