diff --git a/src/interface/desktop/chat.html b/src/interface/desktop/chat.html index b1d0ce48..fbd09daa 100644 --- a/src/interface/desktop/chat.html +++ b/src/interface/desktop/chat.html @@ -115,10 +115,10 @@ return referenceButton; } - function renderMessage(message, by, dt=null, annotations=null) { + function renderMessage(message, by, dt=null, annotations=null, raw=false) { let message_time = formatDate(dt ?? new Date()); let by_name = by == "khoj" ? "🏮 Khoj" : "🤔 You"; - let formattedMessage = formatHTMLMessage(message); + let formattedMessage = formatHTMLMessage(message, raw); let chatBody = document.getElementById("chat-body"); // Create a new div for the chat message @@ -248,7 +248,7 @@ renderMessage(message, by, dt, references); } - function formatHTMLMessage(htmlMessage) { + function formatHTMLMessage(htmlMessage, raw=false) { var md = window.markdownit(); let newHTML = htmlMessage; @@ -267,7 +267,7 @@ }; // Render markdown - newHTML = md.render(newHTML); + newHTML = raw ? newHTML : md.render(newHTML); // Get any elements with a class that starts with "language" let element = document.createElement('div'); element.innerHTML = newHTML; @@ -574,7 +574,7 @@ .trim() .replace(/(\r\n|\n|\r)/gm, ""); - renderMessage(first_run_message, "khoj"); + renderMessage(first_run_message, "khoj", null, null, true); // Disable chat input field and update placeholder text document.getElementById("chat-input").setAttribute("disabled", "disabled"); diff --git a/src/interface/obsidian/src/chat_modal.ts b/src/interface/obsidian/src/chat_modal.ts index 115f4c1f..100fd853 100644 --- a/src/interface/obsidian/src/chat_modal.ts +++ b/src/interface/obsidian/src/chat_modal.ts @@ -41,20 +41,21 @@ export class KhojChatModal extends Modal { let chatBodyEl = contentEl.createDiv({ attr: { id: "khoj-chat-body", class: "khoj-chat-body" } }); // Get chat history from Khoj backend - await this.getChatHistory(chatBodyEl); + let getChatHistorySucessfully = await this.getChatHistory(chatBodyEl); + let placeholderText = getChatHistorySucessfully ? "Chat with Khoj [Hit Enter to send message]" : "Configure Khoj to enable chat"; // Add chat input field let inputRow = contentEl.createDiv("khoj-input-row"); - const chatInput = inputRow.createEl("input", - { - attr: { - type: "text", - id: "khoj-chat-input", - autofocus: "autofocus", - placeholder: "Chat with Khoj [Hit Enter to send message]", - class: "khoj-chat-input option" - } - }) + let chatInput = inputRow.createEl("input", { + attr: { + type: "text", + id: "khoj-chat-input", + autofocus: "autofocus", + placeholder: placeholderText, + class: "khoj-chat-input option", + disabled: !getChatHistorySucessfully ? "disabled" : null + }, + }) let transcribe = inputRow.createEl("button", { text: "Transcribe", @@ -162,7 +163,7 @@ export class KhojChatModal extends Modal { referenceExpandButton.innerHTML = expandButtonText; } - renderMessage(chatEl: Element, message: string, sender: string, dt?: Date): Element { + renderMessage(chatEl: Element, message: string, sender: string, dt?: Date, raw: boolean=false): Element { let message_time = this.formatDate(dt ?? new Date()); let emojified_sender = sender == "khoj" ? "🏮 Khoj" : "🤔 You"; @@ -177,8 +178,12 @@ export class KhojChatModal extends Modal { let chat_message_body_el = chatMessageEl.createDiv(); chat_message_body_el.addClasses(["khoj-chat-message-text", sender]); let chat_message_body_text_el = chat_message_body_el.createDiv(); - // @ts-ignore - MarkdownRenderer.renderMarkdown(message, chat_message_body_text_el, null, null); + if (raw) { + chat_message_body_text_el.innerHTML = message; + } else { + // @ts-ignore + MarkdownRenderer.renderMarkdown(message, chat_message_body_text_el, null, null); + } // Remove user-select: none property to make text selectable chatMessageEl.style.userSelect = "text"; @@ -228,15 +233,33 @@ export class KhojChatModal extends Modal { return `${time_string}, ${date_string}`; } - async getChatHistory(chatBodyEl: Element): Promise { + async getChatHistory(chatBodyEl: Element): Promise { // Get chat history from Khoj backend let chatUrl = `${this.setting.khojUrl}/api/chat/history?client=obsidian`; let headers = { "Authorization": `Bearer ${this.setting.khojApiKey}` }; - let response = await request({ url: chatUrl, headers: headers }); - let chatLogs = JSON.parse(response).response; - chatLogs.forEach((chatLog: any) => { - this.renderMessageWithReferences(chatBodyEl, chatLog.message, chatLog.by, chatLog.context, new Date(chatLog.created), chatLog.intent?.type); - }); + + try { + let response = await fetch(chatUrl, { method: "GET", headers: headers }); + let responseJson: any = await response.json(); + + if (responseJson.detail) { + // If the server returns error details in response, render a setup hint. + let setupMsg = "Hi 👋🏾, to start chatting add available chat models options via the Django Admin panel on the Server"; + this.renderMessage(chatBodyEl, setupMsg, "khoj", undefined, true); + + return false; + } else if (responseJson.response) { + let chatLogs = responseJson.response; + chatLogs.forEach((chatLog: any) => { + this.renderMessageWithReferences(chatBodyEl, chatLog.message, chatLog.by, chatLog.context, new Date(chatLog.created), chatLog.intent?.type); + }); + } + } catch (err) { + let errorMsg = "Unable to get response from Khoj server ❤️‍🩹. Ensure server is running or contact developers for help at team@khoj.dev or on Discord"; + this.renderMessage(chatBodyEl, errorMsg, "khoj", undefined, true); + return false; + } + return true; } async getChatResponse(query: string | undefined | null): Promise { @@ -347,7 +370,8 @@ export class KhojChatModal extends Modal { } } } catch (err) { - this.renderIncrementalMessage(responseElement, "Sorry, unable to get response from Khoj backend ❤️‍🩹. Contact developer for help at team@khoj.dev or in Discord") + let errorMsg = "

Sorry, unable to get response from Khoj backend ❤️‍🩹. Contact developer for help at team@khoj.dev or in Discord

"; + responseElement.innerHTML = errorMsg } } @@ -379,8 +403,9 @@ export class KhojChatModal extends Modal { } else { // If conversation history is cleared successfully, clear chat logs from modal chatBody.innerHTML = ""; - await this.getChatHistory(chatBody); - this.flashStatusInChatInput(result.message); + let getChatHistoryStatus = await this.getChatHistory(chatBody); + let statusMsg = getChatHistoryStatus ? result.message : "Failed to clear conversation history"; + this.flashStatusInChatInput(statusMsg); } } catch (err) { this.flashStatusInChatInput("Failed to clear conversation history"); diff --git a/src/khoj/interface/web/chat.html b/src/khoj/interface/web/chat.html index 2c64d96c..7e6b157f 100644 --- a/src/khoj/interface/web/chat.html +++ b/src/khoj/interface/web/chat.html @@ -124,10 +124,10 @@ To get started, just start typing below. You can also type / to see a list of co return referenceButton; } - function renderMessage(message, by, dt=null, annotations=null) { + function renderMessage(message, by, dt=null, annotations=null, raw=false) { let message_time = formatDate(dt ?? new Date()); let by_name = by == "khoj" ? "🏮 Khoj" : "🤔 You"; - let formattedMessage = formatHTMLMessage(message); + let formattedMessage = formatHTMLMessage(message, raw); let chatBody = document.getElementById("chat-body"); // Create a new div for the chat message @@ -257,7 +257,7 @@ To get started, just start typing below. You can also type / to see a list of co renderMessage(message, by, dt, references); } - function formatHTMLMessage(htmlMessage) { + function formatHTMLMessage(htmlMessage, raw=false) { var md = window.markdownit(); let newHTML = htmlMessage; @@ -276,7 +276,7 @@ To get started, just start typing below. You can also type / to see a list of co }; // Render markdown - newHTML = md.render(newHTML); + newHTML = raw ? newHTML : md.render(newHTML); // Get any elements with a class that starts with "language" let element = document.createElement('div'); element.innerHTML = newHTML; @@ -539,7 +539,8 @@ To get started, just start typing below. You can also type / to see a list of co .then(data => { if (data.detail) { // If the server returns a 500 error with detail, render a setup hint. - renderMessage("Hi 👋🏾, to start chatting add available chat models options via the Django Admin panel on the Server", "khoj"); + let setupMsg = "Hi 👋🏾, to start chatting add available chat models options via the Django Admin panel on the Server"; + renderMessage(setupMsg, "khoj", null, null, true); // Disable chat input field and update placeholder text document.getElementById("chat-input").setAttribute("disabled", "disabled");