From ccc74b9490ee33f8352807884e00efb0a4a1275d Mon Sep 17 00:00:00 2001 From: Daniel LaForce Date: Thu, 1 May 2025 21:41:48 -0600 Subject: [PATCH 1/3] Feat: Add tag similarity logic to main knowledge graph Aligns main graph post connections with individual post page logic (explicit related_posts + tag similarity fallback). Reverts manual related_posts addition. --- src/content/posts/gitops-with-flux-cd.md | 3 + src/pages/blog/index.astro | 71 ++++++++++++++++++------ 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/content/posts/gitops-with-flux-cd.md b/src/content/posts/gitops-with-flux-cd.md index 9c5b74e..32ba7a3 100644 --- a/src/content/posts/gitops-with-flux-cd.md +++ b/src/content/posts/gitops-with-flux-cd.md @@ -11,6 +11,9 @@ tags: - ci-cd - automation readTime: 10 min read +related_posts: + - k3s-cluster + - gitea-self-hosted-git --- # GitOps with Flux CD diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro index ffc17fa..db64706 100644 --- a/src/pages/blog/index.astro +++ b/src/pages/blog/index.astro @@ -63,7 +63,9 @@ const graphData = { edges: [] }; -// Create edges between posts and their tags +// Create edges between posts and their tags, and between related posts +const processedPostPairs = new Set(); // Keep track of processed pairs to avoid duplicate edges + sortedPosts .filter(post => !post.data.draft) .forEach(post => { @@ -78,22 +80,59 @@ sortedPosts strength: 1 }); }); - - // Check if post references other posts (optional) - // This requires a related_posts field in frontmatter - if (post.data.related_posts && Array.isArray(post.data.related_posts)) { - post.data.related_posts.forEach(relatedSlug => { - // Make sure related post exists - if (sortedPosts.some(p => p.slug === relatedSlug)) { - graphData.edges.push({ - source: post.slug, - target: relatedSlug, - type: 'post-post', - strength: 2 - }); - } - }); + + // --- Combined Related Posts Logic --- + let explicitRelatedSlugs = new Set(post.data.related_posts || []); + let relatedPostsForGraph = []; + + // 1. Add explicitly related posts + explicitRelatedSlugs.forEach(relatedSlug => { + const relatedPost = sortedPosts.find(p => p.slug === relatedSlug && !p.data.draft); + if (relatedPost) { + relatedPostsForGraph.push(relatedPost); + } + }); + + // 2. Add implicitly related posts by tag similarity (if needed, up to a limit, e.g., 3 total) + const MAX_RELATED = 3; // Max related posts to show connections for + const MIN_SHARED_TAGS = 2; // Minimum shared tags for implicit relation + + if (relatedPostsForGraph.length < MAX_RELATED && postTags.length > 0) { + sortedPosts + .filter(otherPost => + !otherPost.data.draft && + otherPost.slug !== post.slug && // Not the same post + !explicitRelatedSlugs.has(otherPost.slug) && // Not already explicitly related + !relatedPostsForGraph.some(rp => rp.slug === otherPost.slug) // Not already added + ) + .forEach(otherPost => { + if (relatedPostsForGraph.length >= MAX_RELATED) return; // Stop if we have enough + + const otherTags = otherPost.data.tags || []; + const sharedTags = postTags.filter(tag => otherTags.includes(tag)); + + if (sharedTags.length >= MIN_SHARED_TAGS) { + relatedPostsForGraph.push(otherPost); + } + }); } + + // 3. Create edges for all found related posts (explicit + implicit) + relatedPostsForGraph.forEach(relatedPost => { + const pairKey1 = `${post.slug}-${relatedPost.slug}`; + const pairKey2 = `${relatedPost.slug}-${post.slug}`; + + // Avoid duplicate edges (A->B and B->A) + if (!processedPostPairs.has(pairKey1) && !processedPostPairs.has(pairKey2)) { + graphData.edges.push({ + source: post.slug, + target: relatedPost.slug, + type: 'post-post', // Use consistent type + strength: explicitRelatedSlugs.has(relatedPost.slug) ? 3 : 1.5 // Stronger link if explicit + }); + processedPostPairs.add(pairKey1); // Mark pair as processed + } + }); }); // Terminal commands for tech effect From dba0eac3e4786fc0bb35e90577d8e7f68d024125 Mon Sep 17 00:00:00 2001 From: Daniel LaForce Date: Thu, 1 May 2025 22:01:11 -0600 Subject: [PATCH 2/3] Revert "Feat: Add tag similarity logic to main knowledge graph" This reverts commit ccc74b9490ee33f8352807884e00efb0a4a1275d. --- src/content/posts/gitops-with-flux-cd.md | 3 - src/pages/blog/index.astro | 71 ++++++------------------ 2 files changed, 16 insertions(+), 58 deletions(-) diff --git a/src/content/posts/gitops-with-flux-cd.md b/src/content/posts/gitops-with-flux-cd.md index 32ba7a3..9c5b74e 100644 --- a/src/content/posts/gitops-with-flux-cd.md +++ b/src/content/posts/gitops-with-flux-cd.md @@ -11,9 +11,6 @@ tags: - ci-cd - automation readTime: 10 min read -related_posts: - - k3s-cluster - - gitea-self-hosted-git --- # GitOps with Flux CD diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro index db64706..ffc17fa 100644 --- a/src/pages/blog/index.astro +++ b/src/pages/blog/index.astro @@ -63,9 +63,7 @@ const graphData = { edges: [] }; -// Create edges between posts and their tags, and between related posts -const processedPostPairs = new Set(); // Keep track of processed pairs to avoid duplicate edges - +// Create edges between posts and their tags sortedPosts .filter(post => !post.data.draft) .forEach(post => { @@ -80,59 +78,22 @@ sortedPosts strength: 1 }); }); - - // --- Combined Related Posts Logic --- - let explicitRelatedSlugs = new Set(post.data.related_posts || []); - let relatedPostsForGraph = []; - - // 1. Add explicitly related posts - explicitRelatedSlugs.forEach(relatedSlug => { - const relatedPost = sortedPosts.find(p => p.slug === relatedSlug && !p.data.draft); - if (relatedPost) { - relatedPostsForGraph.push(relatedPost); - } - }); - - // 2. Add implicitly related posts by tag similarity (if needed, up to a limit, e.g., 3 total) - const MAX_RELATED = 3; // Max related posts to show connections for - const MIN_SHARED_TAGS = 2; // Minimum shared tags for implicit relation - - if (relatedPostsForGraph.length < MAX_RELATED && postTags.length > 0) { - sortedPosts - .filter(otherPost => - !otherPost.data.draft && - otherPost.slug !== post.slug && // Not the same post - !explicitRelatedSlugs.has(otherPost.slug) && // Not already explicitly related - !relatedPostsForGraph.some(rp => rp.slug === otherPost.slug) // Not already added - ) - .forEach(otherPost => { - if (relatedPostsForGraph.length >= MAX_RELATED) return; // Stop if we have enough - - const otherTags = otherPost.data.tags || []; - const sharedTags = postTags.filter(tag => otherTags.includes(tag)); - - if (sharedTags.length >= MIN_SHARED_TAGS) { - relatedPostsForGraph.push(otherPost); - } - }); + + // Check if post references other posts (optional) + // This requires a related_posts field in frontmatter + if (post.data.related_posts && Array.isArray(post.data.related_posts)) { + post.data.related_posts.forEach(relatedSlug => { + // Make sure related post exists + if (sortedPosts.some(p => p.slug === relatedSlug)) { + graphData.edges.push({ + source: post.slug, + target: relatedSlug, + type: 'post-post', + strength: 2 + }); + } + }); } - - // 3. Create edges for all found related posts (explicit + implicit) - relatedPostsForGraph.forEach(relatedPost => { - const pairKey1 = `${post.slug}-${relatedPost.slug}`; - const pairKey2 = `${relatedPost.slug}-${post.slug}`; - - // Avoid duplicate edges (A->B and B->A) - if (!processedPostPairs.has(pairKey1) && !processedPostPairs.has(pairKey2)) { - graphData.edges.push({ - source: post.slug, - target: relatedPost.slug, - type: 'post-post', // Use consistent type - strength: explicitRelatedSlugs.has(relatedPost.slug) ? 3 : 1.5 // Stronger link if explicit - }); - processedPostPairs.add(pairKey1); // Mark pair as processed - } - }); }); // Terminal commands for tech effect From 50c24407f2423e53807a7f843bd101ba157ada4d Mon Sep 17 00:00:00 2001 From: Daniel LaForce Date: Thu, 1 May 2025 22:04:31 -0600 Subject: [PATCH 3/3] Feat: Implement combined related posts logic for main graph Adds tag similarity fallback for post connections on main knowledge graph, ensuring preview functionality remains intact. --- src/pages/blog/index.astro | 68 ++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro index ffc17fa..afca897 100644 --- a/src/pages/blog/index.astro +++ b/src/pages/blog/index.astro @@ -63,13 +63,15 @@ const graphData = { edges: [] }; -// Create edges between posts and their tags +// Create edges between posts and their tags, and between related posts +const processedPostPairs = new Set(); // Avoid duplicate A->B and B->A edges + sortedPosts .filter(post => !post.data.draft) .forEach(post => { const postTags = post.data.tags || []; - // Add edges from post to tags + // 1. Add edges from post to tags postTags.forEach(tag => { graphData.edges.push({ source: post.slug, @@ -78,22 +80,60 @@ sortedPosts strength: 1 }); }); + + // --- Find Related Posts (Explicit + Implicit) --- + const MAX_RELATED_LINKS = 3; + const MIN_SHARED_TAGS_FOR_LINK = 2; - // Check if post references other posts (optional) - // This requires a related_posts field in frontmatter - if (post.data.related_posts && Array.isArray(post.data.related_posts)) { - post.data.related_posts.forEach(relatedSlug => { - // Make sure related post exists - if (sortedPosts.some(p => p.slug === relatedSlug)) { - graphData.edges.push({ - source: post.slug, - target: relatedSlug, - type: 'post-post', - strength: 2 - }); + let relatedLinks = new Map(); // Use Map to store related slug and relation type (explicit/implicit) + + // a. Find explicitly related posts + const explicitSlugs = new Set(post.data.related_posts || []); + explicitSlugs.forEach(slug => { + if (sortedPosts.some(p => p.slug === slug && !p.data.draft)) { + relatedLinks.set(slug, 'explicit'); + } + }); + + // b. Find implicitly related posts by tag similarity (if needed) + if (relatedLinks.size < MAX_RELATED_LINKS && postTags.length > 0) { + const potentialRelated = sortedPosts + .filter(otherPost => + !otherPost.data.draft && + otherPost.slug !== post.slug && // Not the same post + !relatedLinks.has(otherPost.slug) // Not already added + ) + .map(otherPost => { + const otherTags = otherPost.data.tags || []; + const sharedTagsCount = postTags.filter(tag => otherTags.includes(tag)).length; + return { slug: otherPost.slug, score: sharedTagsCount }; + }) + .filter(item => item.score >= MIN_SHARED_TAGS_FOR_LINK) + .sort((a, b) => b.score - a.score); // Sort by most shared tags + + potentialRelated.forEach(item => { + if (relatedLinks.size < MAX_RELATED_LINKS) { + relatedLinks.set(item.slug, 'implicit'); } }); } + + // 2. Create edges for the found related posts + relatedLinks.forEach((relationType, relatedSlug) => { + const pairKey1 = `${post.slug}-${relatedSlug}`; + const pairKey2 = `${relatedSlug}-${post.slug}`; + + if (!processedPostPairs.has(pairKey1) && !processedPostPairs.has(pairKey2)) { + graphData.edges.push({ + source: post.slug, + target: relatedSlug, + type: 'post-post', + strength: relationType === 'explicit' ? 3 : 1.5 // Stronger edge for explicit links + }); + processedPostPairs.add(pairKey1); + processedPostPairs.add(pairKey2); // Add both directions to set + } + }); }); // Terminal commands for tech effect