mirror of
https://github.com/khoj-ai/khoj.git
synced 2024-11-27 17:35:07 +01:00
Merge branch 'features/multi-user-support-khoj' of github.com:khoj-ai/khoj into fix-improve-config-page-on-desktop-and-web-app
This commit is contained in:
commit
08c86927cb
2 changed files with 388 additions and 41 deletions
|
@ -34,32 +34,101 @@
|
|||
let escaped_ref = reference.replaceAll('"', '"');
|
||||
|
||||
// Generate HTML for Chat Reference
|
||||
return `<sup><abbr title="${escaped_ref}" tabindex="0">${index}</abbr></sup>`;
|
||||
let short_ref = escaped_ref.slice(0, 100);
|
||||
short_ref = short_ref.length < escaped_ref.length ? short_ref + "..." : short_ref;
|
||||
let referenceButton = document.createElement('button');
|
||||
referenceButton.innerHTML = short_ref;
|
||||
referenceButton.id = `ref-${index}`;
|
||||
referenceButton.classList.add("reference-button");
|
||||
referenceButton.classList.add("collapsed");
|
||||
referenceButton.tabIndex = 0;
|
||||
|
||||
// Add event listener to toggle full reference on click
|
||||
referenceButton.addEventListener('click', function() {
|
||||
console.log(`Toggling ref-${index}`)
|
||||
if (this.classList.contains("collapsed")) {
|
||||
this.classList.remove("collapsed");
|
||||
this.classList.add("expanded");
|
||||
this.innerHTML = escaped_ref;
|
||||
} else {
|
||||
this.classList.add("collapsed");
|
||||
this.classList.remove("expanded");
|
||||
this.innerHTML = short_ref;
|
||||
}
|
||||
});
|
||||
|
||||
return referenceButton;
|
||||
}
|
||||
|
||||
function renderMessage(message, by, dt=null) {
|
||||
function renderMessage(message, by, dt=null, annotations=null) {
|
||||
let message_time = formatDate(dt ?? new Date());
|
||||
let by_name = by == "khoj" ? "🏮 Khoj" : "🤔 You";
|
||||
let formattedMessage = formatHTMLMessage(message);
|
||||
// Generate HTML for Chat Message and Append to Chat Body
|
||||
document.getElementById("chat-body").innerHTML += `
|
||||
<div data-meta="${by_name} at ${message_time}" class="chat-message ${by}">
|
||||
<div class="chat-message-text ${by}">${formattedMessage}</div>
|
||||
</div>
|
||||
`;
|
||||
let chatBody = document.getElementById("chat-body");
|
||||
|
||||
// Create a new div for the chat message
|
||||
let chatMessage = document.createElement('div');
|
||||
chatMessage.className = `chat-message ${by}`;
|
||||
chatMessage.dataset.meta = `${by_name} at ${message_time}`;
|
||||
|
||||
// Create a new div for the chat message text and append it to the chat message
|
||||
let chatMessageText = document.createElement('div');
|
||||
chatMessageText.className = `chat-message-text ${by}`;
|
||||
chatMessageText.innerHTML = formattedMessage;
|
||||
chatMessage.appendChild(chatMessageText);
|
||||
|
||||
// Append annotations div to the chat message
|
||||
if (annotations) {
|
||||
chatMessageText.appendChild(annotations);
|
||||
}
|
||||
|
||||
// Append chat message div to chat body
|
||||
chatBody.appendChild(chatMessage);
|
||||
|
||||
// Scroll to bottom of chat-body element
|
||||
document.getElementById("chat-body").scrollTop = document.getElementById("chat-body").scrollHeight;
|
||||
chatBody.scrollTop = chatBody.scrollHeight;
|
||||
}
|
||||
|
||||
function renderMessageWithReference(message, by, context=null, dt=null) {
|
||||
let references = '';
|
||||
if (context) {
|
||||
references = context
|
||||
.map((reference, index) => generateReference(reference, index))
|
||||
.join("<sup>,</sup>");
|
||||
if (context == null || context.length == 0) {
|
||||
renderMessage(message, by, dt);
|
||||
return;
|
||||
}
|
||||
|
||||
renderMessage(message+references, by, dt);
|
||||
let references = document.createElement('div');
|
||||
|
||||
let referenceExpandButton = document.createElement('button');
|
||||
referenceExpandButton.classList.add("reference-expand-button");
|
||||
let expandButtonText = context.length == 1 ? "1 reference" : `${context.length} references`;
|
||||
referenceExpandButton.innerHTML = expandButtonText;
|
||||
|
||||
references.appendChild(referenceExpandButton);
|
||||
|
||||
let referenceSection = document.createElement('div');
|
||||
referenceSection.classList.add("reference-section");
|
||||
referenceSection.classList.add("collapsed");
|
||||
|
||||
referenceExpandButton.addEventListener('click', function() {
|
||||
if (referenceSection.classList.contains("collapsed")) {
|
||||
referenceSection.classList.remove("collapsed");
|
||||
referenceSection.classList.add("expanded");
|
||||
} else {
|
||||
referenceSection.classList.add("collapsed");
|
||||
referenceSection.classList.remove("expanded");
|
||||
}
|
||||
});
|
||||
|
||||
references.classList.add("references");
|
||||
if (context) {
|
||||
for (let index in context) {
|
||||
let reference = context[index];
|
||||
let polishedReference = generateReference(reference, index);
|
||||
referenceSection.appendChild(polishedReference);
|
||||
}
|
||||
}
|
||||
references.appendChild(referenceSection);
|
||||
|
||||
renderMessage(message, by, dt, references);
|
||||
}
|
||||
|
||||
function formatHTMLMessage(htmlMessage) {
|
||||
|
@ -125,12 +194,14 @@
|
|||
const decoder = new TextDecoder();
|
||||
|
||||
function readStream() {
|
||||
let references = null;
|
||||
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);
|
||||
|
||||
newResponseText.appendChild(references);
|
||||
document.getElementById("chat-body").scrollTop = document.getElementById("chat-body").scrollHeight;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -143,11 +214,36 @@
|
|||
|
||||
const rawReference = chunk.split("### compiled references:")[1];
|
||||
const rawReferenceAsJson = JSON.parse(rawReference);
|
||||
let polishedReference = rawReferenceAsJson.map((reference, index) => generateReference(reference, index))
|
||||
.join("<sup>,</sup>");
|
||||
references = document.createElement('div');
|
||||
references.classList.add("references");
|
||||
|
||||
newResponseText.innerHTML += polishedReference;
|
||||
document.getElementById("chat-body").scrollTop = document.getElementById("chat-body").scrollHeight;
|
||||
|
||||
let referenceExpandButton = document.createElement('button');
|
||||
referenceExpandButton.classList.add("reference-expand-button");
|
||||
let expandButtonText = rawReferenceAsJson.length == 1 ? "1 reference" : `${rawReferenceAsJson.length} references`;
|
||||
referenceExpandButton.innerHTML = expandButtonText;
|
||||
|
||||
references.appendChild(referenceExpandButton);
|
||||
|
||||
let referenceSection = document.createElement('div');
|
||||
referenceSection.classList.add("reference-section");
|
||||
referenceSection.classList.add("collapsed");
|
||||
|
||||
referenceExpandButton.addEventListener('click', function() {
|
||||
if (referenceSection.classList.contains("collapsed")) {
|
||||
referenceSection.classList.remove("collapsed");
|
||||
referenceSection.classList.add("expanded");
|
||||
} else {
|
||||
referenceSection.classList.add("collapsed");
|
||||
referenceSection.classList.remove("expanded");
|
||||
}
|
||||
});
|
||||
|
||||
rawReferenceAsJson.forEach((reference, index) => {
|
||||
let polishedReference = generateReference(reference, index);
|
||||
referenceSection.appendChild(polishedReference);
|
||||
});
|
||||
references.appendChild(referenceSection);
|
||||
readStream();
|
||||
} else {
|
||||
// Display response from Khoj
|
||||
|
@ -443,6 +539,83 @@
|
|||
box-shadow: 0 0 12px rgb(119, 156, 46);
|
||||
}
|
||||
|
||||
div.collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.expanded {
|
||||
display: block;
|
||||
}
|
||||
|
||||
div.reference {
|
||||
display: grid;
|
||||
grid-template-rows: auto;
|
||||
grid-auto-flow: row;
|
||||
grid-column-gap: 10px;
|
||||
grid-row-gap: 10px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
div.expanded.reference-section {
|
||||
display: grid;
|
||||
grid-template-rows: auto;
|
||||
grid-auto-flow: row;
|
||||
grid-column-gap: 10px;
|
||||
grid-row-gap: 10px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
button.reference-button {
|
||||
background: var(--background-color);
|
||||
color: var(--main-text-color);
|
||||
border: 1px solid var(--main-text-color);
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
font-size: 14px;
|
||||
font-weight: 300;
|
||||
line-height: 1.5em;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease-in-out;
|
||||
text-align: left;
|
||||
max-height: 50px;
|
||||
transition: max-height 0.3s ease-in-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
button.reference-button.expanded {
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
button.reference-button::before {
|
||||
content: "▶";
|
||||
margin-right: 5px;
|
||||
display: inline-block;
|
||||
transition: transform 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
button.reference-button:active:before,
|
||||
button.reference-button[aria-expanded="true"]::before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
button.reference-expand-button {
|
||||
background: var(--background-color);
|
||||
color: var(--main-text-color);
|
||||
border: 1px dotted var(--main-text-color);
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
font-size: 14px;
|
||||
font-weight: 300;
|
||||
line-height: 1.5em;
|
||||
cursor: pointer;
|
||||
transition: background 0.4s ease-in-out;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
button.reference-expand-button:hover {
|
||||
background: var(--primary-hover);
|
||||
}
|
||||
|
||||
|
||||
.option-enabled:focus {
|
||||
outline: none !important;
|
||||
border:1px solid #475569;
|
||||
|
|
|
@ -33,32 +33,101 @@
|
|||
let escaped_ref = reference.replaceAll('"', '"');
|
||||
|
||||
// Generate HTML for Chat Reference
|
||||
return `<sup><abbr title="${escaped_ref}" tabindex="0">${index}</abbr></sup>`;
|
||||
let short_ref = escaped_ref.slice(0, 100);
|
||||
short_ref = short_ref.length < escaped_ref.length ? short_ref + "..." : short_ref;
|
||||
let referenceButton = document.createElement('button');
|
||||
referenceButton.innerHTML = short_ref;
|
||||
referenceButton.id = `ref-${index}`;
|
||||
referenceButton.classList.add("reference-button");
|
||||
referenceButton.classList.add("collapsed");
|
||||
referenceButton.tabIndex = 0;
|
||||
|
||||
// Add event listener to toggle full reference on click
|
||||
referenceButton.addEventListener('click', function() {
|
||||
console.log(`Toggling ref-${index}`)
|
||||
if (this.classList.contains("collapsed")) {
|
||||
this.classList.remove("collapsed");
|
||||
this.classList.add("expanded");
|
||||
this.innerHTML = escaped_ref;
|
||||
} else {
|
||||
this.classList.add("collapsed");
|
||||
this.classList.remove("expanded");
|
||||
this.innerHTML = short_ref;
|
||||
}
|
||||
});
|
||||
|
||||
return referenceButton;
|
||||
}
|
||||
|
||||
function renderMessage(message, by, dt=null) {
|
||||
function renderMessage(message, by, dt=null, annotations=null) {
|
||||
let message_time = formatDate(dt ?? new Date());
|
||||
let by_name = by == "khoj" ? "🏮 Khoj" : "🤔 You";
|
||||
let formattedMessage = formatHTMLMessage(message);
|
||||
// Generate HTML for Chat Message and Append to Chat Body
|
||||
document.getElementById("chat-body").innerHTML += `
|
||||
<div data-meta="${by_name} at ${message_time}" class="chat-message ${by}">
|
||||
<div class="chat-message-text ${by}">${formattedMessage}</div>
|
||||
</div>
|
||||
`;
|
||||
let chatBody = document.getElementById("chat-body");
|
||||
|
||||
// Create a new div for the chat message
|
||||
let chatMessage = document.createElement('div');
|
||||
chatMessage.className = `chat-message ${by}`;
|
||||
chatMessage.dataset.meta = `${by_name} at ${message_time}`;
|
||||
|
||||
// Create a new div for the chat message text and append it to the chat message
|
||||
let chatMessageText = document.createElement('div');
|
||||
chatMessageText.className = `chat-message-text ${by}`;
|
||||
chatMessageText.innerHTML = formattedMessage;
|
||||
chatMessage.appendChild(chatMessageText);
|
||||
|
||||
// Append annotations div to the chat message
|
||||
if (annotations) {
|
||||
chatMessageText.appendChild(annotations);
|
||||
}
|
||||
|
||||
// Append chat message div to chat body
|
||||
chatBody.appendChild(chatMessage);
|
||||
|
||||
// Scroll to bottom of chat-body element
|
||||
document.getElementById("chat-body").scrollTop = document.getElementById("chat-body").scrollHeight;
|
||||
chatBody.scrollTop = chatBody.scrollHeight;
|
||||
}
|
||||
|
||||
function renderMessageWithReference(message, by, context=null, dt=null) {
|
||||
let references = '';
|
||||
if (context) {
|
||||
references = context
|
||||
.map((reference, index) => generateReference(reference, index))
|
||||
.join("<sup>,</sup>");
|
||||
if (context == null || context.length == 0) {
|
||||
renderMessage(message, by, dt);
|
||||
return;
|
||||
}
|
||||
|
||||
renderMessage(message+references, by, dt);
|
||||
let references = document.createElement('div');
|
||||
|
||||
let referenceExpandButton = document.createElement('button');
|
||||
referenceExpandButton.classList.add("reference-expand-button");
|
||||
let expandButtonText = context.length == 1 ? "1 reference" : `${context.length} references`;
|
||||
referenceExpandButton.innerHTML = expandButtonText;
|
||||
|
||||
references.appendChild(referenceExpandButton);
|
||||
|
||||
let referenceSection = document.createElement('div');
|
||||
referenceSection.classList.add("reference-section");
|
||||
referenceSection.classList.add("collapsed");
|
||||
|
||||
referenceExpandButton.addEventListener('click', function() {
|
||||
if (referenceSection.classList.contains("collapsed")) {
|
||||
referenceSection.classList.remove("collapsed");
|
||||
referenceSection.classList.add("expanded");
|
||||
} else {
|
||||
referenceSection.classList.add("collapsed");
|
||||
referenceSection.classList.remove("expanded");
|
||||
}
|
||||
});
|
||||
|
||||
references.classList.add("references");
|
||||
if (context) {
|
||||
for (let index in context) {
|
||||
let reference = context[index];
|
||||
let polishedReference = generateReference(reference, index);
|
||||
referenceSection.appendChild(polishedReference);
|
||||
}
|
||||
}
|
||||
references.appendChild(referenceSection);
|
||||
|
||||
renderMessage(message, by, dt, references);
|
||||
}
|
||||
|
||||
function formatHTMLMessage(htmlMessage) {
|
||||
|
@ -120,12 +189,14 @@
|
|||
const decoder = new TextDecoder();
|
||||
|
||||
function readStream() {
|
||||
let references = null;
|
||||
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);
|
||||
|
||||
newResponseText.appendChild(references);
|
||||
document.getElementById("chat-body").scrollTop = document.getElementById("chat-body").scrollHeight;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -138,11 +209,36 @@
|
|||
|
||||
const rawReference = chunk.split("### compiled references:")[1];
|
||||
const rawReferenceAsJson = JSON.parse(rawReference);
|
||||
let polishedReference = rawReferenceAsJson.map((reference, index) => generateReference(reference, index))
|
||||
.join("<sup>,</sup>");
|
||||
references = document.createElement('div');
|
||||
references.classList.add("references");
|
||||
|
||||
newResponseText.innerHTML += polishedReference;
|
||||
document.getElementById("chat-body").scrollTop = document.getElementById("chat-body").scrollHeight;
|
||||
|
||||
let referenceExpandButton = document.createElement('button');
|
||||
referenceExpandButton.classList.add("reference-expand-button");
|
||||
let expandButtonText = rawReferenceAsJson.length == 1 ? "1 reference" : `${rawReferenceAsJson.length} references`;
|
||||
referenceExpandButton.innerHTML = expandButtonText;
|
||||
|
||||
references.appendChild(referenceExpandButton);
|
||||
|
||||
let referenceSection = document.createElement('div');
|
||||
referenceSection.classList.add("reference-section");
|
||||
referenceSection.classList.add("collapsed");
|
||||
|
||||
referenceExpandButton.addEventListener('click', function() {
|
||||
if (referenceSection.classList.contains("collapsed")) {
|
||||
referenceSection.classList.remove("collapsed");
|
||||
referenceSection.classList.add("expanded");
|
||||
} else {
|
||||
referenceSection.classList.add("collapsed");
|
||||
referenceSection.classList.remove("expanded");
|
||||
}
|
||||
});
|
||||
|
||||
rawReferenceAsJson.forEach((reference, index) => {
|
||||
let polishedReference = generateReference(reference, index);
|
||||
referenceSection.appendChild(polishedReference);
|
||||
});
|
||||
references.appendChild(referenceSection);
|
||||
readStream();
|
||||
} else {
|
||||
// Display response from Khoj
|
||||
|
@ -237,6 +333,7 @@
|
|||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
return;
|
||||
});
|
||||
|
||||
|
@ -299,6 +396,83 @@
|
|||
padding: 10px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
div.collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.expanded {
|
||||
display: block;
|
||||
}
|
||||
|
||||
div.reference {
|
||||
display: grid;
|
||||
grid-template-rows: auto;
|
||||
grid-auto-flow: row;
|
||||
grid-column-gap: 10px;
|
||||
grid-row-gap: 10px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
div.expanded.reference-section {
|
||||
display: grid;
|
||||
grid-template-rows: auto;
|
||||
grid-auto-flow: row;
|
||||
grid-column-gap: 10px;
|
||||
grid-row-gap: 10px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
button.reference-button {
|
||||
background: var(--background-color);
|
||||
color: var(--main-text-color);
|
||||
border: 1px solid var(--main-text-color);
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
font-size: 14px;
|
||||
font-weight: 300;
|
||||
line-height: 1.5em;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease-in-out;
|
||||
text-align: left;
|
||||
max-height: 50px;
|
||||
transition: max-height 0.3s ease-in-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
button.reference-button.expanded {
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
button.reference-button::before {
|
||||
content: "▶";
|
||||
margin-right: 5px;
|
||||
display: inline-block;
|
||||
transition: transform 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
button.reference-button:active:before,
|
||||
button.reference-button[aria-expanded="true"]::before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
button.reference-expand-button {
|
||||
background: var(--background-color);
|
||||
color: var(--main-text-color);
|
||||
border: 1px dotted var(--main-text-color);
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
font-size: 14px;
|
||||
font-weight: 300;
|
||||
line-height: 1.5em;
|
||||
cursor: pointer;
|
||||
transition: background 0.4s ease-in-out;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
button.reference-expand-button:hover {
|
||||
background: var(--primary-hover);
|
||||
}
|
||||
|
||||
#chat-body {
|
||||
font-size: medium;
|
||||
margin: 0px;
|
||||
|
|
Loading…
Reference in a new issue