mirror of
https://github.com/khoj-ai/khoj.git
synced 2024-11-27 17:35:07 +01:00
Support syncing, searching images from Obsidian plugin
This commit is contained in:
parent
260aa61818
commit
21fe1a917b
4 changed files with 39 additions and 18 deletions
|
@ -1,6 +1,6 @@
|
|||
import { App, SuggestModal, request, MarkdownRenderer, Instruction, Platform } from 'obsidian';
|
||||
import { KhojSetting } from 'src/settings';
|
||||
import { createNoteAndCloseModal, getLinkToEntry } from 'src/utils';
|
||||
import { supportedBinaryFileTypes, createNoteAndCloseModal, getFileFromPath, getLinkToEntry, supportedImageFilesTypes } from 'src/utils';
|
||||
|
||||
export interface SearchResult {
|
||||
entry: string;
|
||||
|
@ -112,28 +112,41 @@ export class KhojSearchModal extends SuggestModal<SearchResult> {
|
|||
let os_path_separator = result.file.includes('\\') ? '\\' : '/';
|
||||
let filename = result.file.split(os_path_separator).pop();
|
||||
|
||||
// Show filename of each search result for context
|
||||
el.createEl("div",{ cls: 'khoj-result-file' }).setText(filename ?? "");
|
||||
let result_el = el.createEl("div", { cls: 'khoj-result-entry' })
|
||||
|
||||
let resultToRender = "";
|
||||
let fileExtension = filename?.split(".").pop() ?? "";
|
||||
if (supportedImageFilesTypes.includes(fileExtension) && filename) {
|
||||
let linkToEntry: string = filename;
|
||||
let imageFiles = this.app.vault.getFiles().filter(file => supportedImageFilesTypes.includes(fileExtension));
|
||||
// Find vault file of chosen search result
|
||||
let fileInVault = getFileFromPath(imageFiles, result.file);
|
||||
if (fileInVault)
|
||||
linkToEntry = this.app.vault.getResourcePath(fileInVault);
|
||||
|
||||
resultToRender = `![](${linkToEntry})`;
|
||||
} else {
|
||||
// Remove YAML frontmatter when rendering string
|
||||
result.entry = result.entry.replace(/---[\n\r][\s\S]*---[\n\r]/, '');
|
||||
|
||||
// Truncate search results to lines_to_render
|
||||
let entry_snipped_indicator = result.entry.split('\n').length > lines_to_render ? ' **...**' : '';
|
||||
let snipped_entry = result.entry.split('\n').slice(0, lines_to_render).join('\n');
|
||||
|
||||
// Show filename of each search result for context
|
||||
el.createEl("div",{ cls: 'khoj-result-file' }).setText(filename ?? "");
|
||||
let result_el = el.createEl("div", { cls: 'khoj-result-entry' })
|
||||
|
||||
resultToRender = `${snipped_entry}${entry_snipped_indicator}`;
|
||||
}
|
||||
// @ts-ignore
|
||||
MarkdownRenderer.renderMarkdown(snipped_entry + entry_snipped_indicator, result_el, result.file, null);
|
||||
MarkdownRenderer.renderMarkdown(resultToRender, result_el, result.file, null);
|
||||
}
|
||||
|
||||
async onChooseSuggestion(result: SearchResult, _: MouseEvent | KeyboardEvent) {
|
||||
// Get all markdown and PDF files in vault
|
||||
// Get all markdown, pdf and image files in vault
|
||||
const mdFiles = this.app.vault.getMarkdownFiles();
|
||||
const pdfFiles = this.app.vault.getFiles().filter(file => file.extension === 'pdf');
|
||||
const binaryFiles = this.app.vault.getFiles().filter(file => supportedBinaryFileTypes.includes(file.extension));
|
||||
|
||||
// Find, Open vault file at heading of chosen search result
|
||||
let linkToEntry = getLinkToEntry(mdFiles.concat(pdfFiles), result.file, result.entry);
|
||||
let linkToEntry = getLinkToEntry(mdFiles.concat(binaryFiles), result.file, result.entry);
|
||||
if (linkToEntry) this.app.workspace.openLinkText(linkToEntry, '');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ export interface UserInfo {
|
|||
email?: string;
|
||||
}
|
||||
|
||||
|
||||
export interface KhojSetting {
|
||||
resultsCount: number;
|
||||
khojUrl: string;
|
||||
|
|
|
@ -48,11 +48,14 @@ function filenameToMimeType (filename: TFile): string {
|
|||
}
|
||||
}
|
||||
|
||||
export const supportedImageFilesTypes = ['png', 'jpg', 'jpeg'];
|
||||
export const supportedBinaryFileTypes = ['pdf'].concat(supportedImageFilesTypes);
|
||||
export const supportedFileTypes = ['md', 'markdown'].concat(supportedBinaryFileTypes);
|
||||
|
||||
export async function updateContentIndex(vault: Vault, setting: KhojSetting, lastSync: Map<TFile, number>, regenerate: boolean = false): Promise<Map<TFile, number>> {
|
||||
// Get all markdown, pdf files in the vault
|
||||
console.log(`Khoj: Updating Khoj content index...`)
|
||||
const files = vault.getFiles().filter(file => file.extension === 'md' || file.extension === 'markdown' || file.extension === 'pdf');
|
||||
const binaryFileTypes = ['pdf']
|
||||
const files = vault.getFiles().filter(file => supportedFileTypes.includes(file.extension));
|
||||
let countOfFilesToIndex = 0;
|
||||
let countOfFilesToDelete = 0;
|
||||
lastSync = lastSync.size > 0 ? lastSync : new Map<TFile, number>();
|
||||
|
@ -66,7 +69,7 @@ export async function updateContentIndex(vault: Vault, setting: KhojSetting, las
|
|||
}
|
||||
|
||||
countOfFilesToIndex++;
|
||||
const encoding = binaryFileTypes.includes(file.extension) ? "binary" : "utf8";
|
||||
const encoding = supportedBinaryFileTypes.includes(file.extension) ? "binary" : "utf8";
|
||||
const mimeType = fileExtensionToMimeType(file.extension) + (encoding === "utf8" ? "; charset=UTF-8" : "");
|
||||
const fileContent = encoding == 'binary' ? await vault.readBinary(file) : await vault.read(file);
|
||||
fileData.push({blob: new Blob([fileContent], { type: mimeType }), path: file.path});
|
||||
|
@ -353,7 +356,7 @@ export function pasteTextAtCursor(text: string | undefined) {
|
|||
}
|
||||
}
|
||||
|
||||
export function getLinkToEntry(sourceFiles: TFile[], chosenFile: string, chosenEntry: string): string | undefined {
|
||||
export function getFileFromPath(sourceFiles: TFile[], chosenFile: string): TFile | undefined {
|
||||
// Find the vault file matching file of chosen file, entry
|
||||
let fileMatch = sourceFiles
|
||||
// Sort by descending length of path
|
||||
|
@ -362,6 +365,12 @@ export function getLinkToEntry(sourceFiles: TFile[], chosenFile: string, chosenE
|
|||
// The first match is the best file match across OS
|
||||
// e.g. Khoj server on Linux, Obsidian vault on Android
|
||||
.find(file => chosenFile.replace(/\\/g, "/").endsWith(file.path))
|
||||
return fileMatch;
|
||||
}
|
||||
|
||||
export function getLinkToEntry(sourceFiles: TFile[], chosenFile: string, chosenEntry: string): string | undefined {
|
||||
// Find the vault file matching file of chosen file, entry
|
||||
let fileMatch = getFileFromPath(sourceFiles, chosenFile);
|
||||
|
||||
// Return link to vault file at heading of chosen search result
|
||||
if (fileMatch) {
|
||||
|
|
|
@ -61,7 +61,7 @@ def test_search_with_invalid_content_type(client):
|
|||
@pytest.mark.django_db(transaction=True)
|
||||
def test_search_with_valid_content_type(client):
|
||||
headers = {"Authorization": "Bearer kk-secret"}
|
||||
for content_type in ["all", "org", "markdown", "image", "pdf", "github", "notion", "plaintext", "docx"]:
|
||||
for content_type in ["all", "org", "markdown", "image", "pdf", "github", "notion", "plaintext", "image", "docx"]:
|
||||
# Act
|
||||
response = client.get(f"/api/search?q=random&t={content_type}", headers=headers)
|
||||
# Assert
|
||||
|
|
Loading…
Reference in a new issue