Spaces:
Sleeping
Sleeping
| 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(); | |
| } | |
| stream = await navigator.mediaDevices.getUserMedia({audio: true, video: false}); | |
| mediaRecorder = new MediaRecorder(stream); | |
| ws = new WebSocket(`wss://brestok-psycological-bot.hf.space/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 { | |
| 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.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("")) | |
| } | |