diff --git a/src/interface/desktop/assets/icons/microphone-solid.svg b/src/interface/desktop/assets/icons/microphone-solid.svg new file mode 100644 index 00000000..3fc4b91d --- /dev/null +++ b/src/interface/desktop/assets/icons/microphone-solid.svg @@ -0,0 +1 @@ + diff --git a/src/interface/desktop/assets/icons/stop-solid.svg b/src/interface/desktop/assets/icons/stop-solid.svg new file mode 100644 index 00000000..a9aaba28 --- /dev/null +++ b/src/interface/desktop/assets/icons/stop-solid.svg @@ -0,0 +1,37 @@ + + diff --git a/src/interface/desktop/chat.html b/src/interface/desktop/chat.html index 4997ef99..6c6d1ca1 100644 --- a/src/interface/desktop/chat.html +++ b/src/interface/desktop/chat.html @@ -377,6 +377,62 @@ chat(); } } + + let mediaRecorder; + async function speechToText() { + const speakButton = document.getElementById('speak-button'); + const speakButtonImg = document.getElementById('speak-button-img'); + const chatInput = document.getElementById('chat-input'); + + const hostURL = await window.hostURLAPI.getURL(); + let url = `${hostURL}/api/speak?client=desktop`; + const khojToken = await window.tokenAPI.getToken(); + const headers = { 'Authorization': `Bearer ${khojToken}` }; + + const sendToServer = (audioBlob) => { + const formData = new FormData(); + formData.append('file', audioBlob); + + fetch(url, { method: 'POST', body: formData, headers}) + .then(response => response.ok ? response.json() : Promise.reject(response)) + .then(data => { chatInput.value += data.text; }) + .catch(err => err.status == 422 ? console.error("Configure speech-to-text model on server.") : console.error("Failed to transcribe audio")); + }; + + const handleRecording = (stream) => { + const audioChunks = []; + const recordingConfig = { mimeType: 'audio/webm' }; + mediaRecorder = new MediaRecorder(stream, recordingConfig); + + mediaRecorder.addEventListener("dataavailable", function(event) { + if (event.data.size > 0) audioChunks.push(event.data); + }); + + mediaRecorder.addEventListener("stop", function() { + const audioBlob = new Blob(audioChunks, { type: 'audio/webm' }); + sendToServer(audioBlob); + }); + + mediaRecorder.start(); + speakButtonImg.src = './assets/icons/stop-solid.svg'; + speakButtonImg.alt = 'Stop Speaking'; + }; + + // Toggle recording + if (!mediaRecorder || mediaRecorder.state === 'inactive') { + navigator.mediaDevices + .getUserMedia({ audio: true }) + .then(handleRecording) + .catch((e) => { + console.error(e); + }); + } else if (mediaRecorder.state === 'recording') { + mediaRecorder.stop(); + speakButtonImg.src = './assets/icons/microphone-solid.svg'; + speakButtonImg.alt = 'Speak'; + } + } +