@deepsweet/mdn 0.2.0 → 0.3.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 +0 -2
  2. package/dist/index.js +35 -32
  3. package/package.json +6 -1
package/README.md CHANGED
@@ -55,7 +55,6 @@ The `stdio` server will spawn [llama.cpp](https://github.com/ggml-org/llama.cpp)
55
55
  | Env variable | Default value | Description |
56
56
  |----------------------------|-----------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------|
57
57
  | `MDN_DATASET_PATH` | HuggingFace cache | Custom dataset directory path |
58
- | `MDN_DATASET_LOCALE` | `en-us` | Dataset language, currently `en-us` only |
59
58
  | `MDN_MODEL_PATH` | HuggingFace cache | Custom model file path |
60
59
  | `MDN_MODEL_TTL` | `1800` | For how long llama.cpp with embedding model should be kept loaded in memory, in seconds; `0` to prevent unloading |
61
60
  | `MDN_QUERY_DESCRIPTION` | `Natural language query for hybrid vector and full-text search` | Custom search query description in case your LLM does a poor job asking the MCP tool |
@@ -64,7 +63,6 @@ The `stdio` server will spawn [llama.cpp](https://github.com/ggml-org/llama.cpp)
64
63
  ## To do
65
64
 
66
65
  - [ ] figure out a better query description so that LLM doesn't over-generate keywords
67
- - [ ] add more dataset [translations](https://github.com/mdn/translated-content/tree/main/files/)
68
66
  - [ ] automatically update and upload the dataset artifacts monthly with GitHub Actions
69
67
 
70
68
  ## License
package/dist/index.js CHANGED
@@ -1,10 +1,28 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/huggingface.ts
4
+ import fs from "node:fs/promises";
5
+ import path from "path";
6
+ import {
7
+ downloadFileToCacheDir,
8
+ getHFHubCachePath,
9
+ getRepoFolderName,
10
+ scanCachedRepo,
11
+ snapshotDownload
12
+ } from "@huggingface/hub";
13
+
14
+ // src/const.ts
15
+ var DATASET_REPO = "deepsweet/mdn";
16
+ var MODEL_REPO = "deepsweet/bge-m3-GGUF-Q4_K_M";
17
+ var MODEL_FILE = "bge-m3-GGUF-Q4_K_M.gguf";
18
+ var MODEL_MAX_TOKENS = 8192;
19
+ var TABLE_NAME = "mdn";
20
+ var TABLE_FILENAME = `${TABLE_NAME}.lance`;
21
+
3
22
  // src/env.ts
4
23
  import { z } from "zod";
5
24
  var env = z.object({
6
25
  MDN_DATASET_PATH: z.string().optional(),
7
- MDN_DATASET_LOCALE: z.enum(["en-us"]).default("en-us"),
8
26
  MDN_MODEL_PATH: z.string().optional(),
9
27
  MDN_MODEL_TTL: z.number().default(1800),
10
28
  MDN_QUERY_DESCRIPTION: z.string().default("Natural language query for hybrid vector and full-text search"),
@@ -12,19 +30,6 @@ var env = z.object({
12
30
  }).parse(process.env);
13
31
 
14
32
  // src/huggingface.ts
15
- import fs from "node:fs/promises";
16
- import path from "path";
17
- import { getHFHubCachePath, getRepoFolderName, scanCachedRepo, snapshotDownload } from "@huggingface/hub";
18
-
19
- // src/utils.ts
20
- var getTableName = (locale) => {
21
- return `mdn-${locale}`;
22
- };
23
-
24
- // src/huggingface.ts
25
- var DATASET_REPO = "deepsweet/mdn";
26
- var MODEL_REPO = "deepsweet/bge-m3-GGUF-Q4_K_M";
27
- var MODEL_FILE = "bge-m3-GGUF-Q4_K_M.gguf";
28
33
  var replaceSymlinksWithHardlinks = async (dir) => {
29
34
  const entries = await fs.readdir(dir, { withFileTypes: true });
30
35
  for (const entry of entries) {
@@ -57,18 +62,17 @@ var getLatestCachedRepoRevision = async (name, type) => {
57
62
  });
58
63
  return latestRevision.path;
59
64
  };
60
- var downloadDataset = async (locale) => {
61
- const tableName = getTableName(locale);
65
+ var downloadDataset = async () => {
62
66
  const dirPath = await snapshotDownload({
63
67
  repo: `datasets/${DATASET_REPO}`,
64
- path: `data/${tableName}.lance`
68
+ path: `data/${TABLE_FILENAME}`
65
69
  });
66
70
  const dataPath = path.join(dirPath, "data");
67
71
  await replaceSymlinksWithHardlinks(dataPath);
68
72
  };
69
73
  var getDatasetPath = async () => {
70
- if (process.env.MDN_DATASET_PATH != null) {
71
- return process.env.MDN_DATASET_PATH;
74
+ if (env.MDN_DATASET_PATH != null) {
75
+ return env.MDN_DATASET_PATH;
72
76
  }
73
77
  const latestRevisionPath = await getLatestCachedRepoRevision(DATASET_REPO, "dataset");
74
78
  const datasetPath = path.join(latestRevisionPath, "data");
@@ -80,8 +84,8 @@ var downloadModel = async () => {
80
84
  });
81
85
  };
82
86
  var getModelPath = async () => {
83
- if (process.env.MDN_MODEL_PATH != null) {
84
- return process.env.MDN_MODEL_PATH;
87
+ if (env.MDN_MODEL_PATH != null) {
88
+ return env.MDN_MODEL_PATH;
85
89
  }
86
90
  const latestRevisionPath = await getLatestCachedRepoRevision(MODEL_REPO, "model");
87
91
  const modelPath = path.join(latestRevisionPath, MODEL_FILE);
@@ -95,15 +99,16 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
95
99
  import { z as z2 } from "zod";
96
100
 
97
101
  // src/llama.ts
102
+ import os from "node:os";
98
103
  import { getLlama, LlamaLogLevel } from "node-llama-cpp";
99
- var MAX_TOKENS = 8192;
100
104
  var getLlamaContext = async (modelPath) => {
105
+ const threads = Math.floor(os.availableParallelism() / 2);
101
106
  const llama = await getLlama({ logLevel: LlamaLogLevel.error });
102
107
  const model = await llama.loadModel({ modelPath });
103
108
  const context = await model.createEmbeddingContext({
104
- contextSize: MAX_TOKENS,
105
- batchSize: MAX_TOKENS,
106
- threads: 0
109
+ contextSize: MODEL_MAX_TOKENS,
110
+ batchSize: MODEL_MAX_TOKENS,
111
+ threads
107
112
  });
108
113
  context.onDispose.createOnceListener(() => {
109
114
  model.dispose().then(() => llama.dispose()).catch(console.error);
@@ -124,7 +129,7 @@ var vectorize = async (context, text) => {
124
129
  // src/query.ts
125
130
  var queryHybrid = async (llamaContext, table, reranker, text) => {
126
131
  const vector = await vectorize(llamaContext, text);
127
- const results = await table.query().nearestTo(vector).fullTextSearch(text).rerank(reranker).limit(env.MDN_SEARCH_RESULTS_LIMIT).toArray();
132
+ const results = await table.query().nearestTo(vector).column("vector").fullTextSearch(text, { columns: "text" }).rerank(reranker).limit(env.MDN_SEARCH_RESULTS_LIMIT).toArray();
128
133
  return results;
129
134
  };
130
135
  var createReranker = async () => {
@@ -134,7 +139,7 @@ var createReranker = async () => {
134
139
 
135
140
  // package.json
136
141
  var name = "@deepsweet/mdn";
137
- var version = "0.2.0";
142
+ var version = "0.3.0";
138
143
 
139
144
  // src/server.ts
140
145
  var startMcpServer = async () => {
@@ -142,8 +147,7 @@ var startMcpServer = async () => {
142
147
  const db = await lancedb2.connect(datasetPath);
143
148
  const reranker = await createReranker();
144
149
  const server = new McpServer({ name, version });
145
- const tableName = getTableName(env.MDN_DATASET_LOCALE);
146
- const table = await db.openTable(tableName);
150
+ const table = await db.openTable(TABLE_NAME);
147
151
  const modelPath = await getModelPath();
148
152
  const llamaTtl = env.MDN_MODEL_TTL * 1000;
149
153
  let llamaContext = null;
@@ -202,8 +206,7 @@ var startMcpServer = async () => {
202
206
  // src/index.ts
203
207
  switch (process.argv[2]) {
204
208
  case "download": {
205
- const locale = process.argv[3] ?? env.MDN_DATASET_LOCALE;
206
- await downloadDataset(locale);
209
+ await downloadDataset();
207
210
  await downloadModel();
208
211
  break;
209
212
  }
@@ -212,7 +215,7 @@ switch (process.argv[2]) {
212
215
  break;
213
216
  }
214
217
  default: {
215
- console.error('Unknown or missing command, use "download" or "server"');
218
+ console.error('Unknown command, use "download" or "server"');
216
219
  process.exit(1);
217
220
  }
218
221
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepsweet/mdn",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -27,13 +27,18 @@
27
27
  "eslint": "^10.1.0",
28
28
  "gray-matter": "^4.0.3",
29
29
  "marked": "^17.0.5",
30
+ "p-all": "^5.0.1",
30
31
  "rimraf": "^6.1.3",
31
32
  "typescript": "^6.0.2"
32
33
  },
33
34
  "scripts": {
35
+ "download": "bun scripts/download.ts",
34
36
  "chunk": "bun scripts/chunk.ts",
35
37
  "ingest": "bun scripts/ingest.ts",
38
+ "update": "bun scripts/update.ts",
36
39
  "query": "bun scripts/query.ts",
40
+ "upload": "bun scripts/upload.ts",
41
+ "test": "bun scripts/test.ts",
37
42
  "check": "tsc --noEmit && eslint --cache scripts/ src/",
38
43
  "dist": "bun build --format esm --target node --packages external --outdir dist/ src/index.ts"
39
44
  },