astro-relatinator 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +14 -7
  2. package/integration.ts +25 -11
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -47,35 +47,42 @@ export default defineConfig({
47
47
 
48
48
  ## Usage
49
49
 
50
- The integration hooks into the Astro build (or dev) process, and will train the model based on the files you've provided. You can then use the `findRelated` function from the package to find related content.
50
+ The integration hooks into the Astro build (or dev) process, and will train the model based on the files you've provided. You can then use the utility functions exported by the package (`BM25Utils` or `TfIdfUtils`, depending on your chosen `similarityMethod`) to find related content and terms.
51
51
 
52
52
  ### Example:
53
53
 
54
54
  ```astro
55
55
  ---
56
56
  import { getCollection } from "astro:content";
57
- import { findRelated } from "astro-relatinator";
57
+ // Import the utils corresponding to your configured similarityMethod
58
+ // (BM25Utils in this example, matching the config example above)
59
+ import { BM25Utils } from "astro-relatinator";
58
60
 
59
61
  const blogEntries = await getCollection("posts"); // assuming your collection is called posts
60
62
  // let's say we want to compare against the first blog entry
61
63
  const first = blogEntries[0];
62
64
 
63
65
  // Concatenate the same fields we used for training and declare how many related posts we want to find
64
- const related = findRelated(`${first.frontmatter.title} ${first.frontmatter.description} ${first.frontmatter.tags.join(' ')} ${first.body}`, first.id, 3)
66
+ const related = await BM25Utils.findRelated(`${first.data.title} ${first.data.description} ${first.data.tags.join(' ')} ${first.body}`, first.id, 3)
65
67
 
66
68
  ---
67
69
 
68
70
  <div>
69
71
  <!-- render your related posts here -->
70
72
  { related.map((id) => {
71
- const post = posts.find((post) => post.id === id);
73
+ const post = blogEntries.find((post) => post.id === id);
74
+ if (!post) return null; // Handle case where post might not be found
72
75
  return (
73
- <a href={post.slug}>
74
- <h2>{post.frontmatter.title}</h2>
75
- <p>{post.frontmatter.description}</p>
76
+ <a href={`/posts/${post.slug}/`}> {/* Adjust href based on your routing */}
77
+ <h2>{post.data.title}</h2>
78
+ <p>{post.data.description}</p>
76
79
  </a>
77
80
  );
78
81
  }) }
79
82
  </div>
80
83
 
81
84
  ```
85
+
86
+ **Note:** The `BM25Utils` and `TfIdfUtils` objects also provide `getTopTermsForId` and `getTopRelatedDocumentsForTerm` functions, similar to the core `relatinator` library.
87
+
88
+ **Development Server:** When running `astro dev`, the integration uses debouncing (a small delay) before re-training the model after a markdown file change. This improves performance for larger sites by preventing rapid, successive re-trains during saves.
package/integration.ts CHANGED
@@ -101,6 +101,8 @@ const relatinatorIntegration = ({
101
101
  name: "astro-relatinator",
102
102
  hooks: {
103
103
  "astro:server:setup": async ({ server, logger }) => {
104
+ let debounceTimeout: NodeJS.Timeout | null = null;
105
+ const debounceMs = 500; // Debounce delay in milliseconds
104
106
  logger.info("relatinator server:setup");
105
107
 
106
108
  logger.info(
@@ -114,23 +116,35 @@ const relatinatorIntegration = ({
114
116
  await trainModel(similarityMethod, paths, schema, debug);
115
117
  logger.info("Initial training done.");
116
118
 
117
- server.watcher.on("all", async (eventName, filePath) => {
119
+ server.watcher.on("all", (eventName, filePath) => {
118
120
  if (!["add", "change"].includes(eventName)) {
119
121
  return;
120
122
  }
121
123
 
122
124
  if (path.extname(filePath).includes("md")) {
123
- logger.info(
124
- `Markdown file changed: ${filePath}; Re-training ${similarityMethod}...`
125
- );
126
- if (similarityMethod === "tfidf") {
127
- await TfIdfUtils.getInstance();
128
- } else {
129
- await BM25Utils.getInstance();
125
+ // Clear existing timer if there is one
126
+ if (debounceTimeout) {
127
+ clearTimeout(debounceTimeout);
130
128
  }
131
- await trainModel(similarityMethod, paths, schema, debug);
132
- } else {
133
- return;
129
+
130
+ // Set a new timer
131
+ debounceTimeout = setTimeout(async () => {
132
+ logger.info(
133
+ `Debounced: Markdown file changed: ${filePath}; Re-training ${similarityMethod}...`
134
+ );
135
+ try {
136
+ // Reset the instance before re-training
137
+ if (similarityMethod === "tfidf") {
138
+ await TfIdfUtils.resetInstance();
139
+ } else {
140
+ await BM25Utils.resetInstance();
141
+ }
142
+ await trainModel(similarityMethod, paths, schema, debug);
143
+ logger.info("Debounced re-training complete.");
144
+ } catch (error) {
145
+ logger.error(`Error during debounced re-training: ${error}`);
146
+ }
147
+ }, debounceMs);
134
148
  }
135
149
  });
136
150
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro-relatinator",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "Find related content in your Astro website or app",
5
5
  "author": "Darko Bozhinovski <dbozhinovski@gmail.com>",
6
6
  "license": "MIT",
@@ -36,7 +36,7 @@
36
36
  "dependencies": {
37
37
  "glob": "^11.0.1",
38
38
  "gray-matter": "^4.0.3",
39
- "relatinator": "2.0.1"
39
+ "relatinator": "2.1.0"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "astro": ">=5"