mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-03 21:29:08 +00:00
Merge branch 'master' into add-speak-to-chat
- Conflicts:
- src/interface/desktop/chat.html
Combine and use common class names for speak component
- src/khoj/database/adapters/__init__.py
Combine imports
- src/khoj/interface/web/chat.html
Combine and use common class names for speak component
- src/khoj/routers/api.py
Combine imports
This commit is contained in:
1
src/interface/desktop/assets/icons/trash-solid.svg
Normal file
1
src/interface/desktop/assets/icons/trash-solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>
|
||||
|
After Width: | Height: | Size: 503 B |
@@ -60,6 +60,52 @@
|
||||
return referenceButton;
|
||||
}
|
||||
|
||||
function generateOnlineReference(reference, index) {
|
||||
|
||||
// Generate HTML for Chat Reference
|
||||
let title = reference.title;
|
||||
let link = reference.link;
|
||||
let snippet = reference.snippet;
|
||||
let question = reference.question;
|
||||
if (question) {
|
||||
question = `<b>Question:</b> ${question}<br><br>`;
|
||||
} else {
|
||||
question = "";
|
||||
}
|
||||
|
||||
let linkElement = document.createElement('a');
|
||||
linkElement.setAttribute('href', link);
|
||||
linkElement.setAttribute('target', '_blank');
|
||||
linkElement.setAttribute('rel', 'noopener noreferrer');
|
||||
linkElement.classList.add("inline-chat-link");
|
||||
linkElement.classList.add("reference-link");
|
||||
linkElement.setAttribute('title', title);
|
||||
linkElement.innerHTML = title;
|
||||
|
||||
let referenceButton = document.createElement('button');
|
||||
referenceButton.innerHTML = linkElement.outerHTML;
|
||||
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 = linkElement.outerHTML + `<br><br>${question + snippet}`;
|
||||
} else {
|
||||
this.classList.add("collapsed");
|
||||
this.classList.remove("expanded");
|
||||
this.innerHTML = linkElement.outerHTML;
|
||||
}
|
||||
});
|
||||
|
||||
return referenceButton;
|
||||
}
|
||||
|
||||
function renderMessage(message, by, dt=null, annotations=null) {
|
||||
let message_time = formatDate(dt ?? new Date());
|
||||
let by_name = by == "khoj" ? "🏮 Khoj" : "🤔 You";
|
||||
@@ -90,8 +136,48 @@
|
||||
chatBody.scrollTop = chatBody.scrollHeight;
|
||||
}
|
||||
|
||||
function renderMessageWithReference(message, by, context=null, dt=null) {
|
||||
if (context == null || context.length == 0) {
|
||||
function processOnlineReferences(referenceSection, onlineContext) {
|
||||
let numOnlineReferences = 0;
|
||||
for (let subquery in onlineContext) {
|
||||
let onlineReference = onlineContext[subquery];
|
||||
if (onlineReference.organic && onlineReference.organic.length > 0) {
|
||||
numOnlineReferences += onlineReference.organic.length;
|
||||
for (let index in onlineReference.organic) {
|
||||
let reference = onlineReference.organic[index];
|
||||
let polishedReference = generateOnlineReference(reference, index);
|
||||
referenceSection.appendChild(polishedReference);
|
||||
}
|
||||
}
|
||||
|
||||
if (onlineReference.knowledgeGraph && onlineReference.knowledgeGraph.length > 0) {
|
||||
numOnlineReferences += onlineReference.knowledgeGraph.length;
|
||||
for (let index in onlineReference.knowledgeGraph) {
|
||||
let reference = onlineReference.knowledgeGraph[index];
|
||||
let polishedReference = generateOnlineReference(reference, index);
|
||||
referenceSection.appendChild(polishedReference);
|
||||
}
|
||||
}
|
||||
|
||||
if (onlineReference.peopleAlsoAsk && onlineReference.peopleAlsoAsk.length > 0) {
|
||||
numOnlineReferences += onlineReference.peopleAlsoAsk.length;
|
||||
for (let index in onlineReference.peopleAlsoAsk) {
|
||||
let reference = onlineReference.peopleAlsoAsk[index];
|
||||
let polishedReference = generateOnlineReference(reference, index);
|
||||
referenceSection.appendChild(polishedReference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return numOnlineReferences;
|
||||
}
|
||||
|
||||
function renderMessageWithReference(message, by, context=null, dt=null, onlineContext=null) {
|
||||
if (context == null && onlineContext == null) {
|
||||
renderMessage(message, by, dt);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((context && context.length == 0) && (onlineContext == null || (onlineContext && Object.keys(onlineContext).length == 0))) {
|
||||
renderMessage(message, by, dt);
|
||||
return;
|
||||
}
|
||||
@@ -100,8 +186,11 @@
|
||||
|
||||
let referenceExpandButton = document.createElement('button');
|
||||
referenceExpandButton.classList.add("reference-expand-button");
|
||||
let expandButtonText = context.length == 1 ? "1 reference" : `${context.length} references`;
|
||||
referenceExpandButton.innerHTML = expandButtonText;
|
||||
let numReferences = 0;
|
||||
|
||||
if (context) {
|
||||
numReferences += context.length;
|
||||
}
|
||||
|
||||
references.appendChild(referenceExpandButton);
|
||||
|
||||
@@ -127,6 +216,14 @@
|
||||
referenceSection.appendChild(polishedReference);
|
||||
}
|
||||
}
|
||||
|
||||
if (onlineContext) {
|
||||
numReferences += processOnlineReferences(referenceSection, onlineContext);
|
||||
}
|
||||
|
||||
let expandButtonText = numReferences == 1 ? "1 reference" : `${numReferences} references`;
|
||||
referenceExpandButton.innerHTML = expandButtonText;
|
||||
|
||||
references.appendChild(referenceSection);
|
||||
|
||||
renderMessage(message, by, dt, references);
|
||||
@@ -140,6 +237,8 @@
|
||||
newHTML = newHTML.replace(/__([\s\S]*?)__/g, '<u>$1</u>');
|
||||
// Remove any text between <s>[INST] and </s> tags. These are spurious instructions for the AI chat model.
|
||||
newHTML = newHTML.replace(/<s>\[INST\].+(<\/s>)?/g, '');
|
||||
// For any text that has single backticks, replace them with <code> tags
|
||||
newHTML = newHTML.replace(/`([^`]+)`/g, '<code class="chat-response">$1</code>');
|
||||
return newHTML;
|
||||
}
|
||||
|
||||
@@ -221,15 +320,28 @@
|
||||
|
||||
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");
|
||||
|
||||
let numReferences = 0;
|
||||
|
||||
// If rawReferenceAsJson is a list, then count the length
|
||||
if (Array.isArray(rawReferenceAsJson)) {
|
||||
numReferences = rawReferenceAsJson.length;
|
||||
|
||||
rawReferenceAsJson.forEach((reference, index) => {
|
||||
let polishedReference = generateReference(reference, index);
|
||||
referenceSection.appendChild(polishedReference);
|
||||
});
|
||||
} else {
|
||||
numReferences += processOnlineReferences(referenceSection, rawReferenceAsJson);
|
||||
}
|
||||
|
||||
references.appendChild(referenceExpandButton);
|
||||
|
||||
referenceExpandButton.addEventListener('click', function() {
|
||||
if (referenceSection.classList.contains("collapsed")) {
|
||||
referenceSection.classList.remove("collapsed");
|
||||
@@ -240,10 +352,8 @@
|
||||
}
|
||||
});
|
||||
|
||||
rawReferenceAsJson.forEach((reference, index) => {
|
||||
let polishedReference = generateReference(reference, index);
|
||||
referenceSection.appendChild(polishedReference);
|
||||
});
|
||||
let expandButtonText = numReferences == 1 ? "1 reference" : `${numReferences} references`;
|
||||
referenceExpandButton.innerHTML = expandButtonText;
|
||||
references.appendChild(referenceSection);
|
||||
readStream();
|
||||
} else {
|
||||
@@ -276,6 +386,9 @@
|
||||
let chatInput = document.getElementById("chat-input");
|
||||
chatInput.value = chatInput.value.trimStart();
|
||||
|
||||
let questionStarterSuggestions = document.getElementById("question-starters");
|
||||
questionStarterSuggestions.style.display = "none";
|
||||
|
||||
if (chatInput.value.startsWith("/") && chatInput.value.split(" ").length === 1) {
|
||||
let chatTooltip = document.getElementById("chat-tooltip");
|
||||
chatTooltip.style.display = "block";
|
||||
@@ -324,7 +437,7 @@
|
||||
const khojToken = await window.tokenAPI.getToken();
|
||||
const headers = { 'Authorization': `Bearer ${khojToken}` };
|
||||
|
||||
fetch(`${hostURL}/api/chat/history?client=web`, { headers })
|
||||
fetch(`${hostURL}/api/chat/history?client=desktop`, { headers })
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.detail) {
|
||||
@@ -351,13 +464,38 @@
|
||||
.then(response => {
|
||||
// Render conversation history, if any
|
||||
response.forEach(chat_log => {
|
||||
renderMessageWithReference(chat_log.message, chat_log.by, chat_log.context, new Date(chat_log.created));
|
||||
renderMessageWithReference(chat_log.message, chat_log.by, chat_log.context, new Date(chat_log.created), chat_log.onlineContext);
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
return;
|
||||
});
|
||||
|
||||
fetch(`${hostURL}/api/chat/starters?client=desktop`, { headers })
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// Render chat options, if any
|
||||
if (data) {
|
||||
let questionStarterSuggestions = document.getElementById("question-starters");
|
||||
for (let index in data) {
|
||||
let questionStarter = data[index];
|
||||
let questionStarterButton = document.createElement('button');
|
||||
questionStarterButton.innerHTML = questionStarter;
|
||||
questionStarterButton.classList.add("question-starter");
|
||||
questionStarterButton.addEventListener('click', function() {
|
||||
questionStarterSuggestions.style.display = "none";
|
||||
document.getElementById("chat-input").value = questionStarter;
|
||||
chat();
|
||||
});
|
||||
questionStarterSuggestions.appendChild(questionStarterButton);
|
||||
}
|
||||
questionStarterSuggestions.style.display = "grid";
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
return;
|
||||
});
|
||||
|
||||
fetch(`${hostURL}/api/chat/options`, { headers })
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
@@ -378,6 +516,32 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function clearConversationHistory() {
|
||||
let chatInput = document.getElementById("chat-input");
|
||||
let originalPlaceholder = chatInput.placeholder;
|
||||
let chatBody = document.getElementById("chat-body");
|
||||
|
||||
const hostURL = await window.hostURLAPI.getURL();
|
||||
const khojToken = await window.tokenAPI.getToken();
|
||||
const headers = { 'Authorization': `Bearer ${khojToken}` };
|
||||
|
||||
fetch(`${hostURL}/api/chat/history?client=desktop`, { method: "DELETE", headers })
|
||||
.then(response => response.ok ? response.json() : Promise.reject(response))
|
||||
.then(data => {
|
||||
chatBody.innerHTML = "";
|
||||
loadChat();
|
||||
chatInput.placeholder = "Cleared conversation history";
|
||||
})
|
||||
.catch(err => {
|
||||
chatInput.placeholder = "Failed to clear conversation history";
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
chatInput.placeholder = originalPlaceholder;
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
let mediaRecorder;
|
||||
async function speechToText() {
|
||||
const speakButton = document.getElementById('speak-button');
|
||||
@@ -453,13 +617,19 @@
|
||||
<!-- Chat Body -->
|
||||
<div id="chat-body"></div>
|
||||
|
||||
<!-- Chat Suggestions -->
|
||||
<div id="question-starters" style="display: none;"></div>
|
||||
|
||||
<!-- Chat Footer -->
|
||||
<div id="chat-footer">
|
||||
<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 id="speak-button" onclick="speechToText()">
|
||||
<img id="speak-button-img" src="./assets/icons/microphone-solid.svg" alt="Speak"></img>
|
||||
<button id="speak-button" class="input-row-button" onclick="speechToText()">
|
||||
<img id="speak-button-img" src="input-row-button-img" src="./assets/icons/microphone-solid.svg" alt="Speak"></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>
|
||||
@@ -583,7 +753,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
|
||||
@@ -606,7 +776,7 @@
|
||||
#chat-input:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
#speak-button {
|
||||
.input-row-button {
|
||||
background: var(--background-color);
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
@@ -617,13 +787,13 @@
|
||||
cursor: pointer;
|
||||
transition: background 0.3s ease-in-out;
|
||||
}
|
||||
#speak-button:hover {
|
||||
.input-row-button:hover {
|
||||
background: var(--primary-hover);
|
||||
}
|
||||
#speak-button:active {
|
||||
.input-row-button:active {
|
||||
background: var(--primary-active);
|
||||
}
|
||||
#speak-button-img {
|
||||
.input-row-button-img {
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
@@ -657,6 +827,38 @@
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
div#question-starters {
|
||||
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
|
||||
grid-column-gap: 8px;
|
||||
}
|
||||
|
||||
button.question-starter {
|
||||
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: 75px;
|
||||
transition: max-height 0.3s ease-in-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
code.chat-response {
|
||||
background: var(--primary-hover);
|
||||
color: var(--primary-inverse);
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
font-size: 14px;
|
||||
font-weight: 300;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
button.reference-button {
|
||||
background: var(--background-color);
|
||||
color: var(--main-text-color);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Khoj",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "An AI copilot for your Second Brain",
|
||||
"author": "Saba Imran, Debanjum Singh Solanky <team@khoj.dev>",
|
||||
"license": "GPL-3.0-or-later",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
;; Saba Imran <saba@khoj.dev>
|
||||
;; Description: An AI copilot for your Second Brain
|
||||
;; Keywords: search, chat, org-mode, outlines, markdown, pdf, image
|
||||
;; Version: 1.0.0
|
||||
;; Version: 1.0.1
|
||||
;; Package-Requires: ((emacs "27.1") (transient "0.3.0") (dash "2.19.1"))
|
||||
;; URL: https://github.com/khoj-ai/khoj/tree/master/src/interface/emacs
|
||||
|
||||
@@ -98,6 +98,11 @@
|
||||
:group 'khoj
|
||||
:type 'string)
|
||||
|
||||
(defcustom khoj-auto-index t
|
||||
"Should content be automatically re-indexed every `khoj-index-interval' seconds."
|
||||
:group 'khoj
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom khoj-index-interval 3600
|
||||
"Interval (in seconds) to wait before updating content index."
|
||||
:group 'khoj
|
||||
@@ -405,14 +410,16 @@ Auto invokes setup steps on calling main entrypoint."
|
||||
;; render response from indexing API endpoint on server
|
||||
(lambda (status)
|
||||
(if (not status)
|
||||
(message "khoj.el: %scontent index %supdated" (if content-type (format "%s " content-type) "") (if force "force " ""))
|
||||
(with-current-buffer (current-buffer)
|
||||
(goto-char "\n\n")
|
||||
(message "khoj.el: Failed to %supdate %s content index. Status: %s. Response: %s"
|
||||
(if force "force " "")
|
||||
content-type
|
||||
status
|
||||
(string-trim (buffer-substring-no-properties (point) (point-max)))))))
|
||||
(message "khoj.el: %scontent index %supdated" (if content-type (format "%s " content-type) "all ") (if force "force " ""))
|
||||
(progn
|
||||
(khoj--delete-open-network-connections-to-server)
|
||||
(with-current-buffer (current-buffer)
|
||||
(search-forward "\n\n" nil t)
|
||||
(message "khoj.el: Failed to %supdate %s content index. Status: %s%s"
|
||||
(if force "force " "")
|
||||
(if content-type (format "%s " content-type) "all")
|
||||
(string-trim (format "%s %s" (nth 1 (nth 1 status)) (nth 2 (nth 1 status))))
|
||||
(if (> (- (point-max) (point)) 0) (format ". Response: %s" (string-trim (buffer-substring-no-properties (point) (point-max)))) ""))))))
|
||||
nil t t)))
|
||||
(setq khoj--indexed-files files-to-index)))
|
||||
|
||||
@@ -444,8 +451,9 @@ Use `BOUNDARY' to separate files. This is sent to Khoj server as a POST request.
|
||||
(when khoj--index-timer
|
||||
(cancel-timer khoj--index-timer))
|
||||
;; Send files to index on server every `khoj-index-interval' seconds
|
||||
(setq khoj--index-timer
|
||||
(run-with-timer 60 khoj-index-interval 'khoj--server-index-files))
|
||||
(when khoj-auto-index
|
||||
(setq khoj--index-timer
|
||||
(run-with-timer 60 khoj-index-interval 'khoj--server-index-files)))
|
||||
|
||||
|
||||
;; -------------------------------------------
|
||||
@@ -858,7 +866,7 @@ RECEIVE-DATE is the message receive date."
|
||||
(let ((proc-buf (buffer-name (process-buffer proc)))
|
||||
(khoj-network-proc-buf (string-join (split-string khoj-server-url "://") " ")))
|
||||
(when (string-match (format "%s" khoj-network-proc-buf) proc-buf)
|
||||
(delete-process proc)))))
|
||||
(ignore-errors (delete-process proc))))))
|
||||
|
||||
(defun khoj--teardown-incremental-search ()
|
||||
"Teardown hooks used for incremental search."
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "khoj",
|
||||
"name": "Khoj",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "An AI copilot for your Second Brain",
|
||||
"author": "Khoj Inc.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Khoj",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "An AI copilot for your Second Brain",
|
||||
"author": "Debanjum Singh Solanky, Saba Imran <team@khoj.dev>",
|
||||
"license": "GPL-3.0-or-later",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { App, Modal, request } from 'obsidian';
|
||||
import { App, Modal, request, setIcon } from 'obsidian';
|
||||
import { KhojSetting } from 'src/settings';
|
||||
import fetch from "node-fetch";
|
||||
|
||||
@@ -38,7 +38,8 @@ export class KhojChatModal extends Modal {
|
||||
await this.getChatHistory();
|
||||
|
||||
// Add chat input field
|
||||
const chatInput = contentEl.createEl("input",
|
||||
let inputRow = contentEl.createDiv("khoj-input-row");
|
||||
const chatInput = inputRow.createEl("input",
|
||||
{
|
||||
attr: {
|
||||
type: "text",
|
||||
@@ -50,6 +51,15 @@ export class KhojChatModal extends Modal {
|
||||
})
|
||||
chatInput.addEventListener('change', (event) => { this.result = (<HTMLInputElement>event.target).value });
|
||||
|
||||
let clearChat = inputRow.createEl("button", {
|
||||
text: "Clear History",
|
||||
attr: {
|
||||
class: "khoj-input-row-button",
|
||||
},
|
||||
})
|
||||
clearChat.addEventListener('click', async (_) => { await this.clearConversationHistory() });
|
||||
setIcon(clearChat, "trash");
|
||||
|
||||
// Scroll to bottom of modal, till the send message input box
|
||||
this.modalEl.scrollTop = this.modalEl.scrollHeight;
|
||||
chatInput.focus();
|
||||
@@ -194,4 +204,35 @@ export class KhojChatModal extends Modal {
|
||||
this.renderIncrementalMessage(responseElement, "Sorry, unable to get response from Khoj backend ❤️🩹. Contact developer for help at team@khoj.dev or <a href='https://discord.gg/BDgyabRM6e'>in Discord</a>")
|
||||
}
|
||||
}
|
||||
|
||||
async clearConversationHistory() {
|
||||
let chatInput = <HTMLInputElement>this.contentEl.getElementsByClassName("khoj-chat-input")[0];
|
||||
let originalPlaceholder = chatInput.placeholder;
|
||||
let chatBody = this.contentEl.getElementsByClassName("khoj-chat-body")[0];
|
||||
|
||||
let response = await request({
|
||||
url: `${this.setting.khojUrl}/api/chat/history?client=web`,
|
||||
method: "DELETE",
|
||||
headers: { "Authorization": `Bearer ${this.setting.khojApiKey}` },
|
||||
})
|
||||
try {
|
||||
let result = JSON.parse(response);
|
||||
if (result.status !== "ok") {
|
||||
// Throw error if conversation history isn't cleared
|
||||
throw new Error("Failed to clear conversation history");
|
||||
} else {
|
||||
// If conversation history is cleared successfully, clear chat logs from modal
|
||||
chatBody.innerHTML = "";
|
||||
await this.getChatHistory();
|
||||
chatInput.placeholder = result.message;
|
||||
}
|
||||
} catch (err) {
|
||||
chatInput.placeholder = "Failed to clear conversation history";
|
||||
} finally {
|
||||
// Reset to original placeholder text after some time
|
||||
setTimeout(() => {
|
||||
chatInput.placeholder = originalPlaceholder;
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ If your plugin does not need CSS, delete this file.
|
||||
}
|
||||
/* color chat bubble by khoj blue */
|
||||
.khoj-chat-message-text.khoj {
|
||||
color: var(--text-on-accent);
|
||||
color: var(--khoj-chat-dark-grey);
|
||||
background: var(--khoj-chat-primary);
|
||||
margin-left: auto;
|
||||
white-space: pre-line;
|
||||
@@ -110,9 +110,12 @@ If your plugin does not need CSS, delete this file.
|
||||
grid-column-gap: 10px;
|
||||
grid-row-gap: 10px;
|
||||
}
|
||||
#khoj-chat-footer > * {
|
||||
padding: 15px;
|
||||
background: #f9fafc
|
||||
.khoj-input-row {
|
||||
display: grid;
|
||||
grid-template-columns: auto 32px;
|
||||
grid-column-gap: 10px;
|
||||
grid-row-gap: 10px;
|
||||
background: var(--background-primary);
|
||||
}
|
||||
#khoj-chat-input.option:hover {
|
||||
box-shadow: 0 0 11px var(--background-modifier-box-shadow);
|
||||
@@ -121,6 +124,25 @@ If your plugin does not need CSS, delete this file.
|
||||
font-size: var(--font-ui-medium);
|
||||
padding: 25px 20px;
|
||||
}
|
||||
.khoj-input-row-button {
|
||||
background: var(--background-primary);
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
--icon-size: var(--icon-size);
|
||||
height: auto;
|
||||
font-size: 14px;
|
||||
font-weight: 300;
|
||||
line-height: 1.5em;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s ease-in-out;
|
||||
}
|
||||
.khoj-input-row-button:hover {
|
||||
background: var(--background-modifier-hover);
|
||||
}
|
||||
.khoj-input-row-button:active {
|
||||
background: var(--background-modifier-active);
|
||||
}
|
||||
|
||||
@media (pointer: coarse), (hover: none) {
|
||||
#khoj-chat-body.abbr[title] {
|
||||
|
||||
@@ -27,5 +27,6 @@
|
||||
"0.12.3": "0.15.0",
|
||||
"0.13.0": "0.15.0",
|
||||
"0.14.0": "0.15.0",
|
||||
"1.0.0": "0.15.0"
|
||||
"1.0.0": "0.15.0",
|
||||
"1.0.1": "0.15.0"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user