mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-07 05:40:17 +00:00
Improve server status check and message in Obsidian client (#617)
- Update health API to pass authenticated users their info - Improve Khoj server status check in Khoj Obsidian client - Show Khoj Obsidian commands even if no connection to server - Show Khoj chat by default in Obsidian side pane instead of search
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
import { Notice, Plugin, request } from 'obsidian';
|
import { Plugin } from 'obsidian';
|
||||||
import { KhojSetting, KhojSettingTab, DEFAULT_SETTINGS } from 'src/settings'
|
import { KhojSetting, KhojSettingTab, DEFAULT_SETTINGS } from 'src/settings'
|
||||||
import { KhojSearchModal } from 'src/search_modal'
|
import { KhojSearchModal } from 'src/search_modal'
|
||||||
import { KhojChatModal } from 'src/chat_modal'
|
import { KhojChatModal } from 'src/chat_modal'
|
||||||
import { updateContentIndex } from './utils';
|
import { updateContentIndex, canConnectToBackend } from './utils';
|
||||||
|
|
||||||
|
|
||||||
export default class Khoj extends Plugin {
|
export default class Khoj extends Plugin {
|
||||||
@@ -16,41 +16,26 @@ export default class Khoj extends Plugin {
|
|||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: 'search',
|
id: 'search',
|
||||||
name: 'Search',
|
name: 'Search',
|
||||||
checkCallback: (checking) => {
|
callback: () => { new KhojSearchModal(this.app, this.settings).open(); }
|
||||||
if (!checking && this.settings.connectedToBackend)
|
|
||||||
new KhojSearchModal(this.app, this.settings).open();
|
|
||||||
return this.settings.connectedToBackend;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add similar notes command. It can only be triggered from the editor
|
// Add similar notes command. It can only be triggered from the editor
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: 'similar',
|
id: 'similar',
|
||||||
name: 'Find similar notes',
|
name: 'Find similar notes',
|
||||||
editorCheckCallback: (checking) => {
|
editorCallback: () => { new KhojSearchModal(this.app, this.settings, true).open(); }
|
||||||
if (!checking && this.settings.connectedToBackend)
|
|
||||||
new KhojSearchModal(this.app, this.settings, true).open();
|
|
||||||
return this.settings.connectedToBackend;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add chat command. It can be triggered from anywhere
|
// Add chat command. It can be triggered from anywhere
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: 'chat',
|
id: 'chat',
|
||||||
name: 'Chat',
|
name: 'Chat',
|
||||||
checkCallback: (checking) => {
|
callback: () => { new KhojChatModal(this.app, this.settings).open(); }
|
||||||
if (!checking && this.settings.connectedToBackend)
|
|
||||||
new KhojChatModal(this.app, this.settings).open();
|
|
||||||
return this.settings.connectedToBackend;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create an icon in the left ribbon.
|
// Create an icon in the left ribbon.
|
||||||
this.addRibbonIcon('search', 'Khoj', (_: MouseEvent) => {
|
this.addRibbonIcon('message-circle', 'Khoj', (_: MouseEvent) => {
|
||||||
// Called when the user clicks the icon.
|
new KhojChatModal(this.app, this.settings).open()
|
||||||
this.settings.connectedToBackend
|
|
||||||
? new KhojSearchModal(this.app, this.settings).open()
|
|
||||||
: new Notice(`❗️Ensure Khoj backend is running and Khoj URL is pointing to it in the plugin settings`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add a settings tab so the user can configure khoj
|
// Add a settings tab so the user can configure khoj
|
||||||
@@ -70,22 +55,9 @@ export default class Khoj extends Plugin {
|
|||||||
// Load khoj obsidian plugin settings
|
// Load khoj obsidian plugin settings
|
||||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||||
|
|
||||||
// Check if khoj backend is configured, note if cannot connect to backend
|
// Check if can connect to khoj server
|
||||||
let headers = { "Authorization": `Bearer ${this.settings.khojApiKey}` };
|
({ connectedToBackend: this.settings.connectedToBackend } =
|
||||||
|
await canConnectToBackend(this.settings.khojUrl, this.settings.khojApiKey, true));
|
||||||
if (this.settings.khojApiKey === "" && this.settings.khojUrl === "https://app.khoj.dev") {
|
|
||||||
new Notice(`❗️Khoj API key is not configured. Please visit https://app.khoj.dev/config#clients to get an API key.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await request({ url: this.settings.khojUrl ,method: "GET", headers: headers })
|
|
||||||
.then(response => {
|
|
||||||
this.settings.connectedToBackend = true;
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
this.settings.connectedToBackend = false;
|
|
||||||
new Notice(`❗️Ensure Khoj backend is running and Khoj URL is pointing to it in the plugin settings.\n\n${error}`);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveSettings() {
|
async saveSettings() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { App, Notice, PluginSettingTab, Setting, TFile } from 'obsidian';
|
import { App, Notice, PluginSettingTab, Setting, TFile } from 'obsidian';
|
||||||
import Khoj from 'src/main';
|
import Khoj from 'src/main';
|
||||||
import { updateContentIndex } from './utils';
|
import { canConnectToBackend, getBackendStatusMessage, updateContentIndex } from './utils';
|
||||||
|
|
||||||
export interface KhojSetting {
|
export interface KhojSetting {
|
||||||
resultsCount: number;
|
resultsCount: number;
|
||||||
@@ -9,6 +9,7 @@ export interface KhojSetting {
|
|||||||
connectedToBackend: boolean;
|
connectedToBackend: boolean;
|
||||||
autoConfigure: boolean;
|
autoConfigure: boolean;
|
||||||
lastSyncedFiles: TFile[];
|
lastSyncedFiles: TFile[];
|
||||||
|
userEmail: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_SETTINGS: KhojSetting = {
|
export const DEFAULT_SETTINGS: KhojSetting = {
|
||||||
@@ -17,7 +18,8 @@ export const DEFAULT_SETTINGS: KhojSetting = {
|
|||||||
khojApiKey: '',
|
khojApiKey: '',
|
||||||
connectedToBackend: false,
|
connectedToBackend: false,
|
||||||
autoConfigure: true,
|
autoConfigure: true,
|
||||||
lastSyncedFiles: []
|
lastSyncedFiles: [],
|
||||||
|
userEmail: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
export class KhojSettingTab extends PluginSettingTab {
|
export class KhojSettingTab extends PluginSettingTab {
|
||||||
@@ -33,7 +35,15 @@ export class KhojSettingTab extends PluginSettingTab {
|
|||||||
containerEl.empty();
|
containerEl.empty();
|
||||||
|
|
||||||
// Add notice whether able to connect to khoj backend or not
|
// Add notice whether able to connect to khoj backend or not
|
||||||
containerEl.createEl('small', { text: this.getBackendStatusMessage() });
|
let backendStatusEl = containerEl.createEl('small', {
|
||||||
|
text: getBackendStatusMessage(
|
||||||
|
this.plugin.settings.connectedToBackend,
|
||||||
|
this.plugin.settings.userEmail,
|
||||||
|
this.plugin.settings.khojUrl,
|
||||||
|
this.plugin.settings.khojApiKey
|
||||||
|
)}
|
||||||
|
);
|
||||||
|
let backendStatusMessage: string = '';
|
||||||
|
|
||||||
// Add khoj settings configurable from the plugin settings tab
|
// Add khoj settings configurable from the plugin settings tab
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
@@ -43,8 +53,14 @@ export class KhojSettingTab extends PluginSettingTab {
|
|||||||
.setValue(`${this.plugin.settings.khojUrl}`)
|
.setValue(`${this.plugin.settings.khojUrl}`)
|
||||||
.onChange(async (value) => {
|
.onChange(async (value) => {
|
||||||
this.plugin.settings.khojUrl = value.trim().replace(/\/$/, '');
|
this.plugin.settings.khojUrl = value.trim().replace(/\/$/, '');
|
||||||
|
({
|
||||||
|
connectedToBackend: this.plugin.settings.connectedToBackend,
|
||||||
|
userEmail: this.plugin.settings.userEmail,
|
||||||
|
statusMessage: backendStatusMessage,
|
||||||
|
} = await canConnectToBackend(this.plugin.settings.khojUrl, this.plugin.settings.khojApiKey));
|
||||||
|
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
containerEl.firstElementChild?.setText(this.getBackendStatusMessage());
|
backendStatusEl.setText(backendStatusMessage);
|
||||||
}));
|
}));
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Khoj API Key')
|
.setName('Khoj API Key')
|
||||||
@@ -53,7 +69,13 @@ export class KhojSettingTab extends PluginSettingTab {
|
|||||||
.setValue(`${this.plugin.settings.khojApiKey}`)
|
.setValue(`${this.plugin.settings.khojApiKey}`)
|
||||||
.onChange(async (value) => {
|
.onChange(async (value) => {
|
||||||
this.plugin.settings.khojApiKey = value.trim();
|
this.plugin.settings.khojApiKey = value.trim();
|
||||||
|
({
|
||||||
|
connectedToBackend: this.plugin.settings.connectedToBackend,
|
||||||
|
userEmail: this.plugin.settings.userEmail,
|
||||||
|
statusMessage: backendStatusMessage,
|
||||||
|
} = await canConnectToBackend(this.plugin.settings.khojUrl, this.plugin.settings.khojApiKey));
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
|
backendStatusEl.setText(backendStatusMessage);
|
||||||
}));
|
}));
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Results Count')
|
.setName('Results Count')
|
||||||
@@ -123,10 +145,4 @@ export class KhojSettingTab extends PluginSettingTab {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBackendStatusMessage() {
|
|
||||||
return !this.plugin.settings.connectedToBackend
|
|
||||||
? '❗Disconnected from Khoj backend. Ensure Khoj backend is running and Khoj URL is correctly set below.'
|
|
||||||
: '✅ Connected to Khoj backend.';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { FileSystemAdapter, Notice, Vault, Modal, TFile } from 'obsidian';
|
import { FileSystemAdapter, Notice, Vault, Modal, TFile, request } from 'obsidian';
|
||||||
import { KhojSetting } from 'src/settings'
|
import { KhojSetting } from 'src/settings'
|
||||||
|
|
||||||
export function getVaultAbsolutePath(vault: Vault): string {
|
export function getVaultAbsolutePath(vault: Vault): string {
|
||||||
@@ -123,3 +123,50 @@ export async function createNoteAndCloseModal(query: string, modal: Modal, opt?:
|
|||||||
}
|
}
|
||||||
modal.close();
|
modal.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function canConnectToBackend(
|
||||||
|
khojUrl: string,
|
||||||
|
khojApiKey: string,
|
||||||
|
showNotice: boolean = false
|
||||||
|
): Promise<{ connectedToBackend: boolean; statusMessage: string, userEmail: string }> {
|
||||||
|
let connectedToBackend = false;
|
||||||
|
let userEmail: string = '';
|
||||||
|
|
||||||
|
if (!!khojUrl) {
|
||||||
|
let headers = !!khojApiKey ? { "Authorization": `Bearer ${khojApiKey}` } : undefined;
|
||||||
|
await request({ url: `${khojUrl}/api/health`, method: "GET", headers: headers })
|
||||||
|
.then(response => {
|
||||||
|
connectedToBackend = true;
|
||||||
|
userEmail = JSON.parse(response)?.email;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
connectedToBackend = false;
|
||||||
|
console.log(`Khoj connection error:\n\n${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let statusMessage: string = getBackendStatusMessage(connectedToBackend, userEmail, khojUrl, khojApiKey);
|
||||||
|
if (showNotice) new Notice(statusMessage);
|
||||||
|
return { connectedToBackend, statusMessage, userEmail };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBackendStatusMessage(
|
||||||
|
connectedToServer: boolean,
|
||||||
|
userEmail: string,
|
||||||
|
khojUrl: string,
|
||||||
|
khojApiKey: string
|
||||||
|
): string {
|
||||||
|
// Welcome message with default settings. Khoj cloud always expects an API key.
|
||||||
|
if (!!khojApiKey && khojUrl === 'https://app.khoj.dev')
|
||||||
|
return `🌈 Welcome to Khoj! Get your API key from ${khojUrl}/config#clients and set it in the Khoj plugin settings on Obsidian`;
|
||||||
|
|
||||||
|
if (!connectedToServer)
|
||||||
|
return `❗️Could not connect to Khoj at ${khojUrl}. Ensure your can access it`;
|
||||||
|
else if (!userEmail)
|
||||||
|
return `✅ Connected to Khoj. ❗️Get a valid API key from ${khojUrl}/config#clients to log in`;
|
||||||
|
else if (userEmail === 'default@example.com')
|
||||||
|
// Logged in as default user in anonymous mode
|
||||||
|
return `✅ Signed in to Khoj`;
|
||||||
|
else
|
||||||
|
return `✅ Signed in to Khoj as ${userEmail}`;
|
||||||
|
}
|
||||||
|
|||||||
@@ -554,6 +554,8 @@ async def extract_references_and_questions(
|
|||||||
return compiled_references, inferred_queries, defiltered_query
|
return compiled_references, inferred_queries, defiltered_query
|
||||||
|
|
||||||
|
|
||||||
@api.get("/health")
|
@api.get("/health", response_class=Response)
|
||||||
async def health_check():
|
@requires(["authenticated"], status_code=200)
|
||||||
return Response(status_code=200)
|
def health_check(request: Request) -> Response:
|
||||||
|
response_obj = {"email": request.user.object.email}
|
||||||
|
return Response(content=json.dumps(response_obj), media_type="application/json", status_code=200)
|
||||||
|
|||||||
Reference in New Issue
Block a user