diff --git a/documentation/docs/get-started/setup.mdx b/documentation/docs/get-started/setup.mdx
index 9cbb5d8d..29e5083e 100644
--- a/documentation/docs/get-started/setup.mdx
+++ b/documentation/docs/get-started/setup.mdx
@@ -15,7 +15,7 @@ import TabItem from '@theme/TabItem';
```
## Setup
-These are the general setup instructions for Khoj.
+These are the general setup instructions for self-hosted Khoj.
- Make sure [python](https://realpython.com/installing-python/) and [pip](https://pip.pypa.io/en/stable/installation/) are installed on your machine
- Check the [Khoj Emacs docs](/clients/emacs#setup) to setup Khoj with Emacs
@@ -23,7 +23,7 @@ These are the general setup instructions for Khoj.
- Check the [Khoj Obsidian docs](/clients/obsidian#setup) to setup Khoj with Obsidian
Its simpler as it can skip the *configure* step below.
-For Installation, you can either use Docker or install Khoj locally.
+For Installation, you can either use Docker or install the Khoj server locally.
### Installation Option 1 (Docker)
@@ -267,6 +267,18 @@ You can head to http://localhost:42110 to use the web interface. You can also us
## Troubleshoot
+#### Dependency conflict when trying to install Khoj python package with pip
+- **Reason**: When conflicting dependency versions are required by Khoj vs other python packages installed on your system
+- **Fix**: Install Khoj in a python virtual environment using [venv](https://docs.python.org/3/library/venv.html) or [pipx](https://pypa.github.io/pipx) to avoid this dependency conflicts
+- **Process**:
+ 1. Install [pipx](https://pypa.github.io/pipx/#install-pipx)
+ 2. Use `pipx` to install Khoj to avoid dependency conflicts with other python packages.
+ ```shell
+ pipx install khoj-assistant
+ ```
+ 3. Now start `khoj` using the standard steps described earlier
+
+
#### Install fails while building Tokenizer dependency
- **Details**: `pip install khoj-assistant` fails while building the `tokenizers` dependency. Complains about Rust.
- **Fix**: Install Rust to build the tokenizers package. For example on Mac run:
diff --git a/src/interface/desktop/about.html b/src/interface/desktop/about.html
index 83ef1573..ec729df0 100644
--- a/src/interface/desktop/about.html
+++ b/src/interface/desktop/about.html
@@ -5,7 +5,7 @@
Khoj - About
-
+
diff --git a/src/interface/desktop/assets/khoj.css b/src/interface/desktop/assets/khoj.css
index b8157bcc..c2a7d367 100644
--- a/src/interface/desktop/assets/khoj.css
+++ b/src/interface/desktop/assets/khoj.css
@@ -1,6 +1,6 @@
/* Amber Light scheme (Default) */
/* Can be forced with data-theme="light" */
-@import url('https://fonts.googleapis.com/css2?family=Tajawal&display=swap');
+@import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@300;500;700&display=swap');
[data-theme="light"],
:root:not([data-theme="dark"]) {
diff --git a/src/interface/desktop/chat.html b/src/interface/desktop/chat.html
index 6d5ced15..78df9d4c 100644
--- a/src/interface/desktop/chat.html
+++ b/src/interface/desktop/chat.html
@@ -5,7 +5,7 @@
Khoj - Chat
-
+
@@ -104,7 +104,7 @@
linkElement.classList.add("inline-chat-link");
linkElement.classList.add("reference-link");
linkElement.setAttribute('title', title);
- linkElement.innerHTML = title;
+ linkElement.textContent = title;
let referenceButton = document.createElement('button');
referenceButton.innerHTML = linkElement.outerHTML;
@@ -133,7 +133,6 @@
let message_time = formatDate(dt ?? new Date());
let by_name = by == "khoj" ? "🏮 Khoj" : "🤔 You";
let formattedMessage = formatHTMLMessage(message, raw);
- let chatBody = document.getElementById("chat-body");
// Create a new div for the chat message
let chatMessage = document.createElement('div');
@@ -152,6 +151,7 @@
}
// Append chat message div to chat body
+ let chatBody = document.getElementById("chat-body");
chatBody.appendChild(chatMessage);
// Scroll to bottom of chat-body element
@@ -285,9 +285,12 @@
// Render markdown
newHTML = raw ? newHTML : md.render(newHTML);
- // Get any elements with a class that starts with "language"
+ // Set rendered markdown to HTML DOM element
let element = document.createElement('div');
element.innerHTML = newHTML;
+ element.className = "chat-message-text-response";
+
+ // Get any elements with a class that starts with "language"
let codeBlockElements = element.querySelectorAll('[class^="language-"]');
// For each element, add a parent div with the class "programmatic-output"
codeBlockElements.forEach((codeElement) => {
@@ -341,22 +344,20 @@
let chat_body = document.getElementById("chat-body");
let conversationID = chat_body.dataset.conversationId;
-
let hostURL = await window.hostURLAPI.getURL();
+ const khojToken = await window.tokenAPI.getToken();
+ const headers = { 'Authorization': `Bearer ${khojToken}` };
if (!conversationID) {
- let response = await fetch(`${hostURL}/api/chat/sessions`, { method: "POST" });
+ let response = await fetch(`${hostURL}/api/chat/sessions`, { method: "POST", headers });
let data = await response.json();
conversationID = data.conversation_id;
chat_body.dataset.conversationId = conversationID;
await refreshChatSessionsPanel();
}
-
// Generate backend API URL to execute query
- let url = `${hostURL}/api/chat?q=${encodeURIComponent(query)}&n=${resultsCount}&client=web&stream=true&conversation_id=${conversationID}®ion=${region}&city=${city}&country=${countryName}`;
- const khojToken = await window.tokenAPI.getToken();
- const headers = { 'Authorization': `Bearer ${khojToken}` };
+ let chatApi = `${hostURL}/api/chat?q=${encodeURIComponent(query)}&n=${resultsCount}&client=web&stream=true&conversation_id=${conversationID}®ion=${region}&city=${city}&country=${countryName}`;
let new_response = document.createElement("div");
new_response.classList.add("chat-message", "khoj");
@@ -379,8 +380,8 @@
let chatInput = document.getElementById("chat-input");
chatInput.classList.remove("option-enabled");
- // Call specified Khoj API
- let response = await fetch(url, { headers });
+ // Call Khoj chat API
+ let response = await fetch(chatApi, { headers });
let rawResponse = "";
const contentType = response.headers.get("content-type");
@@ -540,6 +541,7 @@
chatInput.value = chatInput.value.trimStart();
let questionStarterSuggestions = document.getElementById("question-starters");
+ questionStarterSuggestions.innerHTML = "";
questionStarterSuggestions.style.display = "none";
if (chatInput.value.startsWith("/") && chatInput.value.split(" ").length === 1) {
@@ -591,6 +593,7 @@
const headers = { 'Authorization': `Bearer ${khojToken}` };
let chatBody = document.getElementById("chat-body");
+ chatBody.innerHTML = "";
let conversationId = chatBody.dataset.conversationId;
let chatHistoryUrl = `/api/chat/history?client=desktop`;
if (conversationId) {
@@ -671,11 +674,11 @@
fetch(`${hostURL}/api/chat/starters?client=desktop`, { headers })
.then(response => response.json())
.then(data => {
- // Render chat options, if any
+ // Render conversation starters, if any
if (data.length > 0) {
let questionStarterSuggestions = document.getElementById("question-starters");
- for (let index in data) {
- let questionStarter = data[index];
+ questionStarterSuggestions.innerHTML = "";
+ data.forEach((questionStarter) => {
let questionStarterButton = document.createElement('button');
questionStarterButton.innerHTML = questionStarter;
questionStarterButton.classList.add("question-starter");
@@ -685,7 +688,7 @@
chat();
});
questionStarterSuggestions.appendChild(questionStarterButton);
- }
+ });
questionStarterSuggestions.style.display = "grid";
}
})
@@ -785,7 +788,7 @@
let conversationButton = document.createElement('div');
let incomingConversationId = conversation["conversation_id"];
const conversationTitle = conversation["slug"] || `New conversation 🌱`;
- conversationButton.innerHTML = conversationTitle;
+ conversationButton.textContent = conversationTitle;
conversationButton.classList.add("conversation-button");
if (incomingConversationId == conversationId) {
conversationButton.classList.add("selected-conversation");
@@ -883,7 +886,7 @@
fetch(`${hostURL}${editURL}` , { method: "PATCH" })
.then(response => response.ok ? response.json() : Promise.reject(response))
.then(data => {
- conversationButton.innerHTML = newTitle;
+ conversationButton.textContent = newTitle;
})
.catch(err => {
return;
@@ -1014,6 +1017,7 @@
document.getElementById('side-panel').classList.toggle('collapsed');
document.getElementById('new-conversation').classList.toggle('collapsed');
document.getElementById('existing-conversations').classList.toggle('collapsed');
+ document.getElementById('side-panel-collapse').style.transform = document.getElementById('side-panel').classList.contains('collapsed') ? 'rotate(0deg)' : 'rotate(180deg)';
document.getElementById('chat-section-wrapper').classList.toggle('mobile-friendly');
}
@@ -1058,7 +1062,7 @@
id="collapse-side-panel-button"
onclick="handleCollapseSidePanel()"
>
-