|
let audioContext; |
|
let analyser; |
|
let sourceNode; |
|
let mediaRecorder; |
|
let audioChunks = []; |
|
|
|
document.addEventListener("DOMContentLoaded", () => { |
|
const audioResponseElement = document.getElementById("audioResponse"); |
|
const micButton = document.getElementById("micButton"); |
|
const blobs = document.querySelectorAll(".blob"); |
|
|
|
initAudioContext(audioResponseElement); |
|
function initAudioContext(audioElement) { |
|
audioContext = new (window.AudioContext || window.webkitAudioContext)(); |
|
analyser = audioContext.createAnalyser(); |
|
analyser.fftSize = 64; |
|
|
|
if (audioElement && !sourceNode) { |
|
sourceNode = audioContext.createMediaElementSource(audioElement); |
|
sourceNode.connect(analyser); |
|
analyser.connect(audioContext.destination); |
|
} |
|
} |
|
|
|
function startWaitAnimation() { |
|
document.getElementById("thought-bubble").style.display = "block"; |
|
|
|
micButton.classList.add("disabled"); |
|
micButton.disabled = true; |
|
} |
|
|
|
function stopWaitAnimation() { |
|
document.getElementById("thought-bubble").style.display = "none"; |
|
|
|
micButton.classList.remove("disabled"); |
|
micButton.disabled = false; |
|
} |
|
|
|
function enableMicButton() { |
|
micButton.classList.remove("disabled"); |
|
micButton.disabled = false; |
|
} |
|
|
|
function hideBlobs() { |
|
document.querySelector(".blob-container").style.display = "none"; |
|
} |
|
|
|
function showBlobs() { |
|
document.querySelector(".blob-container").style.display = "flex"; |
|
} |
|
|
|
async function startRecording() { |
|
audioChunks = []; |
|
try { |
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); |
|
mediaRecorder = new MediaRecorder(stream, { mimeType: "audio/webm" }); |
|
mediaRecorder.ondataavailable = (event) => audioChunks.push(event.data); |
|
mediaRecorder.start(); |
|
} catch (error) { |
|
console.error("Error accessing audio devices:", error); |
|
micButton.checked = false; |
|
stopWaitAnimation(); |
|
} |
|
} |
|
|
|
function stopRecording() { |
|
mediaRecorder.stop(); |
|
mediaRecorder.onstop = async () => { |
|
const audioBlob = new Blob(audioChunks, { type: "audio/webm" }); |
|
const audioBase64 = await blobToBase64(audioBlob); |
|
sendAudioToServer(audioBase64); |
|
}; |
|
} |
|
|
|
function blobToBase64(blob) { |
|
const reader = new FileReader(); |
|
return new Promise((resolve) => { |
|
reader.onloadend = () => resolve(reader.result.split(",")[1]); |
|
reader.readAsDataURL(blob); |
|
}); |
|
} |
|
function sendAudioToServer(audioBase64) { |
|
fetch( |
|
"https://h8v918qrvg.execute-api.eu-central-1.amazonaws.com/Prod/sts/question", |
|
{ |
|
method: "POST", |
|
headers: { "Content-Type": "text/plain" }, |
|
body: audioBase64, |
|
} |
|
) |
|
.then((response) => response.text()) |
|
.then((data) => { |
|
if (data.message === "Question not provided in POST body") { |
|
console.error("Question not provided in POST body"); |
|
stopWaitAnimation(); |
|
enableMicButton(); |
|
return; |
|
} |
|
|
|
const audioSrc = `data:audio/wav;base64,${data}`; |
|
audioResponseElement.src = audioSrc; |
|
audioResponseElement.play().then(() => { |
|
visualize(); |
|
}); |
|
}) |
|
.catch((error) => { |
|
console.error("Error:", error); |
|
stopWaitAnimation(); |
|
}); |
|
} |
|
|
|
micButton.addEventListener("change", () => { |
|
hideBlobs(); |
|
if (micButton.checked) { |
|
startRecording(); |
|
} else { |
|
stopRecording(); |
|
startWaitAnimation(); |
|
} |
|
}); |
|
|
|
function visualize() { |
|
if (!audioContext) { |
|
console.error("AudioContext not initialized"); |
|
return; |
|
} |
|
|
|
if (!sourceNode) { |
|
console.error("SourceNode not initialized"); |
|
return; |
|
} |
|
const bufferLength = analyser.frequencyBinCount; |
|
const dataArray = new Uint8Array(bufferLength); |
|
|
|
function draw() { |
|
requestAnimationFrame(draw); |
|
analyser.getByteFrequencyData(dataArray); |
|
|
|
const segmentLength = Math.floor(bufferLength / blobs.length); |
|
for (let i = 0; i < blobs.length; i++) { |
|
|
|
const dataValue = dataArray[(i * segmentLength) / 2] || 0; |
|
|
|
const height = (dataValue / 128.0) * 50 + 50; |
|
|
|
blobs[i].style.height = `${height}px`; |
|
} |
|
} |
|
|
|
draw(); |
|
} |
|
|
|
audioResponseElement.onended = () => { |
|
hideBlobs(); |
|
stopWaitAnimation(); |
|
enableMicButton(); |
|
}; |
|
|
|
audioResponseElement.onplay = () => { |
|
showBlobs(); |
|
stopWaitAnimation(); |
|
}; |
|
|
|
document.body.addEventListener("click", () => { |
|
if (audioContext && audioContext.state === "suspended") { |
|
audioContext.resume(); |
|
} |
|
}); |
|
}); |
|
|