brestok's picture
Upload 29 files
c409a15 verified
raw
history blame
5.69 kB
const messageHistory = document.getElementById('chatHistory')
let stream;
let ws
let silenceDetectorNode;
let silenceCount = 0
let recording = false;
let mediaRecorder;
let continuousRecorder
let audioContext;
let source;
let currentAudioChunks = [];
let allAudioChunks = [];
const uuid = generateUUID()
const startRecordingButton = document.getElementById('startRecording')
const loadingModal = document.getElementById('loadingModal');
function makeLoading() {
loadingModal.style.visibility = 'visible';
}
function stopLoading() {
loadingModal.style.visibility = 'hidden';
}
function showMessage(message_text) {
const message = document.getElementById('message');
message.innerText = message_text
message.style.display = 'block';
setTimeout(function () {
message.style.display = 'none';
}, 2000);
}
function createMessage(type, message) {
const newMessage = document.createElement('div')
newMessage.className = 'message rounded-4 bg-white mb-4 mx-4 py-2 px-3 border'
newMessage.innerHTML = `
<h5>${type}</h5>
${message}
`
messageHistory.appendChild(newMessage)
}
function playResponse(data) {
const response = JSON.parse(data)
createMessage('User', response['user_query'])
stopLoading()
console.log(response)
const audioSrc = `data:audio/mp3;base64,${response['voice_response']}`;
const audio = new Audio(audioSrc)
audio.play()
audio.onended = () => {
recording = true
createMessage('Liza', response['ai_response'])
showMessage('You can speak!')
startMediaRecorder()
}
}
startRecordingButton.addEventListener('click', async () => {
if (!recording) {
if (mediaRecorder && mediaRecorder.state !== 'inactive') {
mediaRecorder.stop();
}
ws = new WebSocket(`ws://localhost:8000/ws/${uuid}`);
ws.onclose = (event) => {
if (mediaRecorder && mediaRecorder.state !== 'inactive') {
mediaRecorder.stop();
}
}
ws.onerror = (error) => {
alert('Something was wrong. Try again later.')
console.log(error)
window.location.reload()
};
ws.onmessage = (event) => {
const response = event.data
playResponse(response)
}
startRecordingButton.innerHTML = 'Stop call';
try {
stream = await navigator.mediaDevices.getUserMedia({audio: true, video: false});
audioContext = new AudioContext();
await audioContext.audioWorklet.addModule('../../../static/js/audio-processor.js');
silenceDetectorNode = new AudioWorkletNode(audioContext, 'silence-detector-processor');
silenceDetectorNode.port.onmessage = (event) => {
if (event.data.type === 'silence') {
if (currentAudioChunks.length > 0) {
if (silenceCount === 0) {
silenceCount += 1;
stopRecorder();
}
}
} else if (event.data.type === 'sound') {
silenceCount = 0;
}
};
source = audioContext.createMediaStreamSource(stream);
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.start(1000);
mediaRecorder.ondataavailable = event => {
currentAudioChunks.push(event.data);
};
source.connect(silenceDetectorNode).connect(audioContext.destination);
continuousRecorder = new MediaRecorder(stream);
continuousRecorder.start();
continuousRecorder.ondataavailable = event => {
allAudioChunks.push(event.data);
};
recording = true;
} catch (error) {
console.error('Access to microphone denied:', error);
}
} else {
await stopRecording();
}
});
async function stopRecording() {
// startRecordingButton.innerHTML = 'Start recording';
// recording = false;
// mediaRecorder.stop();
// continuousRecorder.stop();
// silenceDetectorNode.disconnect();
// source.disconnect();
// audioContext.close();
// currentAudioChunks = [];
window.location.reload()
}
function sendAudioToServer(audioBlob) {
return new Promise((resolve, reject) => {
console.log("Sending audio to server...", audioBlob);
const reader = new FileReader();
reader.readAsDataURL(audioBlob);
reader.onloadend = () => {
let base64String = reader.result;
base64String = base64String.split(',')[1];
const dataWS = {'audio': base64String};
ws.send(JSON.stringify(dataWS));
makeLoading()
resolve();
};
reader.onerror = reject;
});
}
async function stopRecorder() {
if (mediaRecorder && mediaRecorder.state !== 'inactive') {
mediaRecorder.stop();
}
await sendAudioToServer(new Blob(currentAudioChunks, {type: 'audio/wav'}));
currentAudioChunks = [];
}
async function startMediaRecorder() {
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.start(1000);
mediaRecorder.ondataavailable = event => {
currentAudioChunks.push(event.data);
}
}
function generateUUID() {
const arr = new Uint8Array(16)
window.crypto.getRandomValues(arr)
arr[6] = (arr[6] & 0x0f) | 0x40
arr[8] = (arr[8] & 0x3f) | 0x80
return ([...arr].map((b, i) =>
(i === 4 || i === 6 || i === 8 || i === 10 ? "-" : "") + b.toString(16).padStart(2, "0")
).join(""))
}