mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-02 21:19:12 +00:00
Resolve merge conflicts for rendering chat response
This commit is contained in:
@@ -292,14 +292,13 @@
|
||||
.then(response => {
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let rawResponse = "";
|
||||
let references = null;
|
||||
|
||||
function readStream() {
|
||||
reader.read().then(({ done, value }) => {
|
||||
if (done) {
|
||||
// Evaluate the contents of new_response_text.innerHTML after all the data has been streamed
|
||||
const currentHTML = newResponseText.innerHTML;
|
||||
newResponseText.innerHTML = formatHTMLMessage(currentHTML);
|
||||
// Append any references after all the data has been streamed
|
||||
newResponseText.appendChild(references);
|
||||
document.getElementById("chat-body").scrollTop = document.getElementById("chat-body").scrollHeight;
|
||||
return;
|
||||
@@ -310,14 +309,15 @@
|
||||
|
||||
if (chunk.includes("### compiled references:")) {
|
||||
const additionalResponse = chunk.split("### compiled references:")[0];
|
||||
newResponseText.innerHTML += additionalResponse;
|
||||
rawResponse += additionalResponse;
|
||||
newResponseText.innerHTML = "";
|
||||
newResponseText.appendChild(formatHTMLMessage(rawResponse));
|
||||
|
||||
const rawReference = chunk.split("### compiled references:")[1];
|
||||
const rawReferenceAsJson = JSON.parse(rawReference);
|
||||
references = document.createElement('div');
|
||||
references.classList.add("references");
|
||||
|
||||
|
||||
let referenceExpandButton = document.createElement('button');
|
||||
referenceExpandButton.classList.add("reference-expand-button");
|
||||
|
||||
@@ -374,7 +374,10 @@
|
||||
}
|
||||
} else {
|
||||
// If the chunk is not a JSON object, just display it as is
|
||||
newResponseText.innerHTML += chunk;
|
||||
rawResponse += chunk;
|
||||
newResponseText.innerHTML = "";
|
||||
newResponseText.appendChild(formatHTMLMessage(rawResponse));
|
||||
|
||||
readStream();
|
||||
}
|
||||
}
|
||||
@@ -529,6 +532,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
function flashStatusInChatInput(message) {
|
||||
// Get chat input element and original placeholder
|
||||
let chatInput = document.getElementById("chat-input");
|
||||
let originalPlaceholder = chatInput.placeholder;
|
||||
// Set placeholder to message
|
||||
chatInput.placeholder = message;
|
||||
// Reset placeholder after 2 seconds
|
||||
setTimeout(() => {
|
||||
chatInput.placeholder = originalPlaceholder;
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
async function clearConversationHistory() {
|
||||
let chatInput = document.getElementById("chat-input");
|
||||
let originalPlaceholder = chatInput.placeholder;
|
||||
@@ -543,17 +558,71 @@
|
||||
.then(data => {
|
||||
chatBody.innerHTML = "";
|
||||
loadChat();
|
||||
chatInput.placeholder = "Cleared conversation history";
|
||||
flashStatusInChatInput("🗑 Cleared conversation history");
|
||||
})
|
||||
.catch(err => {
|
||||
chatInput.placeholder = "Failed to clear conversation history";
|
||||
flashStatusInChatInput("⛔️ Failed to clear conversation history");
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
chatInput.placeholder = originalPlaceholder;
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
let mediaRecorder;
|
||||
async function speechToText() {
|
||||
const speakButtonImg = document.getElementById('speak-button-img');
|
||||
const chatInput = document.getElementById('chat-input');
|
||||
|
||||
const hostURL = await window.hostURLAPI.getURL();
|
||||
let url = `${hostURL}/api/transcribe?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
|
||||
? flashStatusInChatInput("⛔️ Configure speech-to-text model on server.")
|
||||
: flashStatusInChatInput("⛔️ 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 Transcription';
|
||||
};
|
||||
|
||||
// Toggle recording
|
||||
if (!mediaRecorder || mediaRecorder.state === 'inactive') {
|
||||
navigator.mediaDevices
|
||||
.getUserMedia({ audio: true })
|
||||
.then(handleRecording)
|
||||
.catch((e) => {
|
||||
flashStatusInChatInput("⛔️ Failed to access microphone");
|
||||
});
|
||||
} else if (mediaRecorder.state === 'recording') {
|
||||
mediaRecorder.stop();
|
||||
speakButtonImg.src = './assets/icons/microphone-solid.svg';
|
||||
speakButtonImg.alt = 'Transcribe';
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<body>
|
||||
<div id="khoj-empty-container" class="khoj-empty-container">
|
||||
@@ -582,8 +651,11 @@
|
||||
<div id="chat-tooltip" style="display: none;"></div>
|
||||
<div id="input-row">
|
||||
<textarea id="chat-input" class="option" oninput="onChatInput()" onkeydown=incrementalChat(event) autofocus="autofocus" placeholder="Type / to see a list of commands, or just type your questions and hit enter."></textarea>
|
||||
<button class="input-row-button" onclick="clearConversationHistory()">
|
||||
<img class="input-rown-button-img" src="./assets/icons/trash-solid.svg" alt="Clear Chat History"></img>
|
||||
<button id="speak-button" class="input-row-button" onclick="speechToText()">
|
||||
<img id="speak-button-img" class="input-row-button-img" src="./assets/icons/microphone-solid.svg" alt="Transcribe"></img>
|
||||
</button>
|
||||
<button id="clear-chat" class="input-row-button" onclick="clearConversationHistory()">
|
||||
<img class="input-row-button-img" src="./assets/icons/trash-solid.svg" alt="Clear Chat History"></img>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -633,7 +705,6 @@
|
||||
.chat-message.you {
|
||||
margin-right: auto;
|
||||
text-align: right;
|
||||
white-space: pre-line;
|
||||
}
|
||||
/* basic style chat message text */
|
||||
.chat-message-text {
|
||||
@@ -650,7 +721,6 @@
|
||||
color: var(--primary-inverse);
|
||||
background: var(--primary);
|
||||
margin-left: auto;
|
||||
white-space: pre-line;
|
||||
}
|
||||
/* Spinner symbol when the chat message is loading */
|
||||
.spinner {
|
||||
@@ -707,7 +777,7 @@
|
||||
}
|
||||
#input-row {
|
||||
display: grid;
|
||||
grid-template-columns: auto 32px;
|
||||
grid-template-columns: auto 32px 32px;
|
||||
grid-column-gap: 10px;
|
||||
grid-row-gap: 10px;
|
||||
background: #f9fafc
|
||||
|
||||
Reference in New Issue
Block a user