diff --git a/src/khoj/interface/web/chat.html b/src/khoj/interface/web/chat.html index b8571d8e..306bb02f 100644 --- a/src/khoj/interface/web/chat.html +++ b/src/khoj/interface/web/chat.html @@ -639,10 +639,14 @@ To get started, just start typing below. You can also type / to see a list of co }); } + let sendMessageTimeout; let mediaRecorder; - function speechToText() { + function speechToText(event) { + event.preventDefault(); const speakButtonImg = document.getElementById('speak-button-img'); const stopRecordButtonImg = document.getElementById('stop-record-button-img'); + const sendButtonImg = document.getElementById('send-button-img'); + const stopSendButtonImg = document.getElementById('stop-send-button-img'); const chatInput = document.getElementById('chat-input'); const sendToServer = (audioBlob) => { @@ -652,6 +656,29 @@ To get started, just start typing below. You can also type / to see a list of co fetch('/api/transcribe?client=web', { method: 'POST', body: formData }) .then(response => response.ok ? response.json() : Promise.reject(response)) .then(data => { chatInput.value += data.text.trimStart(); autoResize(); }) + .then(() => { + // Don't auto-send empty messages + if (chatInput.value.length === 0) return; + + // Send message after 3 seconds, unless stop send button is clicked + sendButtonImg.style.display = 'none'; + stopSendButtonImg.style.display = 'initial'; + + // Start the countdown timer UI + document.getElementById('countdown-circle').style.animation = "countdown 3s linear 1 forwards"; + + sendMessageTimeout = setTimeout(() => { + // Revert to showing send-button and hide the stop-send-button + sendButtonImg.style.display = 'initial'; + stopSendButtonImg.style.display = 'none'; + + // Stop the countdown timer UI + document.getElementById('countdown-circle').style.animation = "none"; + + // Send message + chat(); + }, 3000); + }) .catch(err => { if (err.status === 501) { flashStatusInChatInput("⛔️ Configure speech-to-text model on server.") @@ -700,6 +727,18 @@ To get started, just start typing below. You can also type / to see a list of co stopRecordButtonImg.style.display = 'none'; } } + + function cancelSendMessage() { + // Cancel the chat() call if the stop-send-button is clicked + clearTimeout(sendMessageTimeout); + + // Revert to showing send-button and hide the stop-send-button + document.getElementById('stop-send-button-img').style.display = 'none'; + document.getElementById('send-button-img').style.display = 'initial'; + + // Stop the countdown timer UI + document.getElementById('countdown-circle').style.animation = "none"; + };
@@ -730,7 +769,8 @@ To get started, just start typing below. You can also type / to see a list of co - -
@@ -1037,8 +1081,8 @@ To get started, just start typing below. You can also type / to see a list of co height: 24px; } #send-button { - padding-top: 0; - padding-right: 3px; + padding: 0; + position: relative; } #send-button-img { width: 28px; @@ -1047,6 +1091,30 @@ To get started, just start typing below. You can also type / to see a list of co border-radius: 50%; } + #stop-send-button-img { + position: absolute; + top: 6px; + right: 6px; + width: 28px; + height: 28px; + transform: rotateY(-180deg) rotateZ(-90deg); + } + #countdown-circle { + stroke-dasharray: 44px; /* The circumference of the circle with 7px radius */ + stroke-dashoffset: 0px; + stroke-linecap: round; + stroke-width: 1px; + stroke: var(--main-text-color); + fill: none; + } + @keyframes countdown { + from { + stroke-dashoffset: 0px; + } + to { + stroke-dashoffset: -44px; /* The circumference of the circle with 7px radius */ + } + } .option-enabled { box-shadow: 0 0 12px rgb(119, 156, 46);