From 733fdcf8ba6e27dae023b1e7b26adfb41bda6d1f Mon Sep 17 00:00:00 2001 From: perf3ct Date: Sat, 8 Mar 2025 23:36:04 +0000 Subject: [PATCH] update relationship weights --- .../llm/embeddings/base_embeddings.ts | 67 +++++++++++++++++-- src/services/llm/embeddings/vector_store.ts | 4 +- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/services/llm/embeddings/base_embeddings.ts b/src/services/llm/embeddings/base_embeddings.ts index be2b1a2a9..29e52d1ce 100644 --- a/src/services/llm/embeddings/base_embeddings.ts +++ b/src/services/llm/embeddings/base_embeddings.ts @@ -29,11 +29,68 @@ export abstract class BaseEmbeddingProvider implements EmbeddingProvider { * Generates a rich text representation of a note's context for embedding */ protected generateNoteContextText(context: NoteEmbeddingContext): string { + // Build a relationship-focused summary first + const relationshipSummary = []; + + // Summarize the note's place in the hierarchy + if (context.parentTitles.length > 0) { + relationshipSummary.push(`This note is a child of: ${context.parentTitles.map(t => this.cleanText(t)).join(', ')}.`); + } + + if (context.childTitles.length > 0) { + relationshipSummary.push(`This note has children: ${context.childTitles.map(t => this.cleanText(t)).join(', ')}.`); + } + + // Emphasize relationships with other notes + if (context.relatedNotes && context.relatedNotes.length > 0) { + // Group by relation type for better understanding + const relationsByType: Record = {}; + for (const rel of context.relatedNotes) { + if (!relationsByType[rel.relationName]) { + relationsByType[rel.relationName] = []; + } + relationsByType[rel.relationName].push(this.cleanText(rel.targetTitle)); + } + + for (const [relType, targets] of Object.entries(relationsByType)) { + relationshipSummary.push(`This note has ${relType} relationship with: ${targets.join(', ')}.`); + } + } + + // Emphasize backlinks for bidirectional relationships + if (context.backlinks && context.backlinks.length > 0) { + // Group by relation type + const backlinksByType: Record = {}; + for (const link of context.backlinks) { + if (!backlinksByType[link.relationName]) { + backlinksByType[link.relationName] = []; + } + backlinksByType[link.relationName].push(this.cleanText(link.sourceTitle)); + } + + for (const [relType, sources] of Object.entries(backlinksByType)) { + relationshipSummary.push(`This note is ${relType} of: ${sources.join(', ')}.`); + } + } + + // Emphasize templates/inheritance + if (context.templateTitles && context.templateTitles.length > 0) { + relationshipSummary.push(`This note inherits from: ${context.templateTitles.map(t => this.cleanText(t)).join(', ')}.`); + } + // Start with core note information let result = `Title: ${this.cleanText(context.title)}\n` + `Type: ${context.type}\n` + - `MIME: ${context.mime}\n` + + `MIME: ${context.mime}\n`; + + // Add the relationship summary at the beginning for emphasis + if (relationshipSummary.length > 0) { + result += `Relationships: ${relationshipSummary.join(' ')}\n`; + } + + // Continue with dates + result += `Created: ${context.dateCreated}\n` + `Modified: ${context.dateModified}\n`; @@ -55,22 +112,21 @@ export abstract class BaseEmbeddingProvider implements EmbeddingProvider { result += labelTexts.join('; ') + '\n'; } - // Add parents concisely + // Parents, children, templates, relations, and backlinks are now handled in the relationship summary + // But we'll include them again in a more structured format for organization + if (context.parentTitles.length > 0) { result += `Parents: ${context.parentTitles.map(t => this.cleanText(t)).join('; ')}\n`; } - // Add children concisely if (context.childTitles.length > 0) { result += `Children: ${context.childTitles.map(t => this.cleanText(t)).join('; ')}\n`; } - // Add template/inheritance relationships concisely if (context.templateTitles && context.templateTitles.length > 0) { result += `Templates: ${context.templateTitles.map(t => this.cleanText(t)).join('; ')}\n`; } - // Add related notes concisely if (context.relatedNotes && context.relatedNotes.length > 0) { result += 'Related: '; const relatedTexts = context.relatedNotes.map(rel => @@ -79,7 +135,6 @@ export abstract class BaseEmbeddingProvider implements EmbeddingProvider { result += relatedTexts.join('; ') + '\n'; } - // Add backlinks concisely if (context.backlinks && context.backlinks.length > 0) { result += 'Referenced By: '; const backlinkTexts = context.backlinks.map(link => diff --git a/src/services/llm/embeddings/vector_store.ts b/src/services/llm/embeddings/vector_store.ts index 3c767bb83..b3c2b2f6e 100644 --- a/src/services/llm/embeddings/vector_store.ts +++ b/src/services/llm/embeddings/vector_store.ts @@ -148,7 +148,7 @@ export async function findSimilarNotes( providerId: string, modelId: string, limit = 10, - threshold = 0.7 + threshold = 0.65 // Slightly lowered from 0.7 to account for relationship focus ): Promise<{noteId: string, similarity: number}[]> { // Get all embeddings for the given provider and model const rows = await sql.getRows(` @@ -172,7 +172,7 @@ export async function findSimilarNotes( }; }); - // Filter by threshold and sort by similarity (descending) + // Filter by threshold and sort by similarity (highest first) return similarities .filter(item => item.similarity >= threshold) .sort((a, b) => b.similarity - a.similarity)