d37b9f23bd
This commit adds semantic caching functionality to speed up repeated queries and implements a complete indexing pipeline for processing vault files. The changes include: - Added semantic cache service using ChromaDB for storing and retrieving cached responses - Implemented indexing pipeline with extraction, normalization, and vectorization steps - Added cache configuration settings to the plugin - Updated Ollama client to support cache integration - Added tests for all new indexing components - Extended vault indexer with indexing pipeline support
110 lines
2.8 KiB
TypeScript
110 lines
2.8 KiB
TypeScript
// src/indexing-pipeline/extraction.ts
|
|
|
|
// VaultFile interface is defined locally since it's not exported from types
|
|
interface VaultFile {
|
|
basename: string;
|
|
path: string;
|
|
}
|
|
|
|
export interface Frontmatter {
|
|
title?: string;
|
|
tags?: string;
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
export interface ExtractedContent {
|
|
basename: string;
|
|
path: string;
|
|
content: string;
|
|
frontmatter: Frontmatter;
|
|
headings: string[];
|
|
embeddedCodeBlocks: string[];
|
|
firstParagraph?: string;
|
|
}
|
|
|
|
/**
|
|
* Extracts raw content from a vault file including:
|
|
* - Markdown content
|
|
* - YAML frontmatter
|
|
* - Headings
|
|
* - Embedded code blocks
|
|
* - First paragraph
|
|
*/
|
|
export class ContentExtractor {
|
|
extractFromFile(file: VaultFile, content: string): ExtractedContent {
|
|
const frontmatter: Frontmatter = {};
|
|
const headings: string[] = [];
|
|
const embeddedCodeBlocks: string[] = [];
|
|
let firstParagraph: string | undefined;
|
|
|
|
// Extract frontmatter
|
|
const frontmatterMatch = content.match(/^---(.*?)---/s);
|
|
if (frontmatterMatch) {
|
|
try {
|
|
const frontmatterContent = frontmatterMatch[1];
|
|
const lines = frontmatterContent.trim().split('\n');
|
|
for (const line of lines) {
|
|
const [key, ...valueParts] = line.split(':');
|
|
if (!key) continue;
|
|
const value = valueParts.join(':').trim();
|
|
if (key.trim() === 'title') {
|
|
if (value) {
|
|
frontmatter.title = value;
|
|
}
|
|
} else if (key.trim() === 'tags') {
|
|
if (value) {
|
|
frontmatter.tags = value;
|
|
}
|
|
} else {
|
|
// Store other frontmatter fields as-is
|
|
frontmatter[key.trim()] = value;
|
|
}
|
|
}
|
|
} catch {
|
|
// If frontmatter parsing fails, continue with empty frontmatter
|
|
}
|
|
}
|
|
|
|
// Extract headings
|
|
const headingMatches = content.match(/^#{1,6} (.*?)$/gm);
|
|
if (headingMatches) {
|
|
headings.push(...headingMatches.map((h: string) => h.replace(/^#{1,6} /, '')));
|
|
}
|
|
|
|
// Extract embedded code blocks
|
|
const codeBlockMatches = content.match(/```([\s\S]*?)```/g);
|
|
if (codeBlockMatches) {
|
|
embeddedCodeBlocks.push(...codeBlockMatches);
|
|
}
|
|
|
|
// Extract first paragraph
|
|
const paragraphMatch = content.match(/^([^#]*?)(?=#|\n\n|$)/s);
|
|
if (paragraphMatch) {
|
|
firstParagraph = paragraphMatch[1].trim();
|
|
}
|
|
|
|
return {
|
|
basename: file.basename,
|
|
path: file.path,
|
|
content,
|
|
frontmatter,
|
|
headings,
|
|
embeddedCodeBlocks,
|
|
firstParagraph,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Extracts just the raw text content without headers, frontmatter, etc.
|
|
*/
|
|
extractRawText(content: string): string {
|
|
return content
|
|
.replace(/^---.*?---/s, '')
|
|
.replace(/^#.*?$/gm, '')
|
|
.replace(/```.*?```/gs, '')
|
|
.replace(/`.*?`/g, '')
|
|
.replace(/\[.*?\]\(.*?\)/g, '')
|
|
.trim();
|
|
}
|
|
}
|