zenn-rag 0.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 (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +221 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +68 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/index.d.ts +6 -0
  8. package/dist/commands/index.d.ts.map +1 -0
  9. package/dist/commands/index.js +11 -0
  10. package/dist/commands/index.js.map +1 -0
  11. package/dist/commands/mcp.d.ts +2 -0
  12. package/dist/commands/mcp.d.ts.map +1 -0
  13. package/dist/commands/mcp.js +245 -0
  14. package/dist/commands/mcp.js.map +1 -0
  15. package/dist/commands/search.d.ts +10 -0
  16. package/dist/commands/search.d.ts.map +1 -0
  17. package/dist/commands/search.js +37 -0
  18. package/dist/commands/search.js.map +1 -0
  19. package/dist/commands/status.d.ts +2 -0
  20. package/dist/commands/status.d.ts.map +1 -0
  21. package/dist/commands/status.js +111 -0
  22. package/dist/commands/status.js.map +1 -0
  23. package/dist/config.d.ts +28 -0
  24. package/dist/config.d.ts.map +1 -0
  25. package/dist/config.js +88 -0
  26. package/dist/config.js.map +1 -0
  27. package/dist/embedder.d.ts +17 -0
  28. package/dist/embedder.d.ts.map +1 -0
  29. package/dist/embedder.js +31 -0
  30. package/dist/embedder.js.map +1 -0
  31. package/dist/index.d.ts +12 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +12 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/logger.d.ts +31 -0
  36. package/dist/logger.d.ts.map +1 -0
  37. package/dist/logger.js +56 -0
  38. package/dist/logger.js.map +1 -0
  39. package/dist/parser.d.ts +56 -0
  40. package/dist/parser.d.ts.map +1 -0
  41. package/dist/parser.js +214 -0
  42. package/dist/parser.js.map +1 -0
  43. package/dist/providers/base.d.ts +2 -0
  44. package/dist/providers/base.d.ts.map +1 -0
  45. package/dist/providers/base.js +4 -0
  46. package/dist/providers/base.js.map +1 -0
  47. package/dist/providers/factory.d.ts +4 -0
  48. package/dist/providers/factory.d.ts.map +1 -0
  49. package/dist/providers/factory.js +27 -0
  50. package/dist/providers/factory.js.map +1 -0
  51. package/dist/providers/gemini.d.ts +20 -0
  52. package/dist/providers/gemini.d.ts.map +1 -0
  53. package/dist/providers/gemini.js +79 -0
  54. package/dist/providers/gemini.js.map +1 -0
  55. package/dist/providers/ollama.d.ts +14 -0
  56. package/dist/providers/ollama.d.ts.map +1 -0
  57. package/dist/providers/ollama.js +38 -0
  58. package/dist/providers/ollama.js.map +1 -0
  59. package/dist/providers/openai.d.ts +18 -0
  60. package/dist/providers/openai.d.ts.map +1 -0
  61. package/dist/providers/openai.js +65 -0
  62. package/dist/providers/openai.js.map +1 -0
  63. package/dist/providers/types.d.ts +7 -0
  64. package/dist/providers/types.d.ts.map +1 -0
  65. package/dist/providers/types.js +2 -0
  66. package/dist/providers/types.js.map +1 -0
  67. package/dist/services/sync-service.d.ts +28 -0
  68. package/dist/services/sync-service.d.ts.map +1 -0
  69. package/dist/services/sync-service.js +310 -0
  70. package/dist/services/sync-service.js.map +1 -0
  71. package/dist/store.d.ts +35 -0
  72. package/dist/store.d.ts.map +1 -0
  73. package/dist/store.js +180 -0
  74. package/dist/store.js.map +1 -0
  75. package/dist/types.d.ts +49 -0
  76. package/dist/types.d.ts.map +1 -0
  77. package/dist/types.js +2 -0
  78. package/dist/types.js.map +1 -0
  79. package/package.json +61 -0
@@ -0,0 +1,310 @@
1
+ import fs from "node:fs/promises";
2
+ import { watch as fsWatch } from "node:fs";
3
+ import path from "node:path";
4
+ import { getActiveModel, getContext } from "../config.js";
5
+ import { getEmbedding, getEmbeddings } from "../embedder.js";
6
+ import { computeHash, parseArticleFile, parseBookChapterFile, } from "../parser.js";
7
+ import { ArticleVectorStore } from "../store.js";
8
+ import { getLogger } from "../logger.js";
9
+ export class SyncService {
10
+ logger;
11
+ constructor(logger) {
12
+ this.logger = logger ?? getLogger();
13
+ }
14
+ async loadManifest(manifestPath) {
15
+ try {
16
+ const raw = await fs.readFile(manifestPath, "utf-8");
17
+ return JSON.parse(raw);
18
+ }
19
+ catch {
20
+ return { version: 1, entries: {} };
21
+ }
22
+ }
23
+ async saveManifest(manifestPath, manifest) {
24
+ await fs.mkdir(path.dirname(manifestPath), { recursive: true });
25
+ await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
26
+ }
27
+ /**
28
+ * articles/ および books/ から対象 Markdown ファイルを走査
29
+ */
30
+ async scanContentTargets(articlesDir, booksDir) {
31
+ const targets = [];
32
+ let hasFoundAnyDir = false;
33
+ // 1. articles/
34
+ try {
35
+ const entries = await fs.readdir(articlesDir);
36
+ hasFoundAnyDir = true;
37
+ for (const entry of entries) {
38
+ if (entry.endsWith(".md")) {
39
+ const slug = path.basename(entry, ".md");
40
+ targets.push({
41
+ filePath: path.join(articlesDir, entry),
42
+ slug,
43
+ itemType: "article",
44
+ });
45
+ }
46
+ }
47
+ }
48
+ catch {
49
+ // articles/ がない場合スキップ
50
+ }
51
+ // 2. books/
52
+ try {
53
+ const bookEntries = await fs.readdir(booksDir, { withFileTypes: true });
54
+ hasFoundAnyDir = true;
55
+ for (const bookEntry of bookEntries) {
56
+ if (bookEntry.isDirectory()) {
57
+ const bookSlug = bookEntry.name;
58
+ const bookDirPath = path.join(booksDir, bookSlug);
59
+ try {
60
+ const chapterFiles = await fs.readdir(bookDirPath);
61
+ for (const chFile of chapterFiles) {
62
+ if (chFile.endsWith(".md")) {
63
+ const chSlug = path.basename(chFile, ".md");
64
+ targets.push({
65
+ filePath: path.join(bookDirPath, chFile),
66
+ slug: `${bookSlug}/${chSlug}`,
67
+ itemType: "book",
68
+ bookSlug,
69
+ });
70
+ }
71
+ }
72
+ }
73
+ catch {
74
+ // チャプター読み込みエラーはスキップ
75
+ }
76
+ }
77
+ }
78
+ }
79
+ catch {
80
+ // books/ がない場合スキップ
81
+ }
82
+ if (!hasFoundAnyDir) {
83
+ throw new Error(`記事または本ディレクトリが見つかりません (articles: ${articlesDir}, books: ${booksDir})`);
84
+ }
85
+ return targets;
86
+ }
87
+ async sync(options = {}) {
88
+ const logger = options.logger ?? this.logger;
89
+ const ctx = getContext();
90
+ const active = getActiveModel();
91
+ logger.info("=== Zenn 記事 / 本 インデックス同期 ===");
92
+ logger.info(`プロバイダ: ${active.provider}`);
93
+ logger.info(`Embeddingモデル: ${active.model}`);
94
+ logger.info(`記事ディレクトリ: ${ctx.articlesDir}`);
95
+ logger.info(`本ディレクトリ: ${ctx.booksDir}`);
96
+ logger.info(`Vector DB保存先: ${ctx.vectorDbDir}\n`);
97
+ let manifest = await this.loadManifest(ctx.manifestPath);
98
+ const store = new ArticleVectorStore();
99
+ await store.init();
100
+ logger.write("Embeddingモデルの接続と次元数を確認中... ");
101
+ const testVector = await getEmbedding("health check");
102
+ const currentDim = testVector.length;
103
+ logger.info(`OK (${currentDim}次元)`);
104
+ const dbDim = await store.getVectorDimension();
105
+ const hasExistingEntries = Object.keys(manifest.entries).length > 0;
106
+ const isDimensionMismatch = dbDim !== null && dbDim !== currentDim;
107
+ const isModelChanged = !manifest.model ||
108
+ manifest.provider !== active.provider ||
109
+ manifest.model !== active.model ||
110
+ isDimensionMismatch;
111
+ let isReset = false;
112
+ if (options.force || isDimensionMismatch) {
113
+ isReset = true;
114
+ if (isDimensionMismatch) {
115
+ logger.info(`\n[ベクトルの次元数不一致を検知]`);
116
+ logger.info(` 既存DB: ${dbDim}次元`);
117
+ logger.info(` 新モデル: ${currentDim}次元`);
118
+ logger.info(` ベクトルの次元数が異なるため、Vector DBとマニフェストを自動リセットして全件再インデックスします。\n`);
119
+ }
120
+ else {
121
+ logger.info("[強制再インデックス] 既存のVector DBとマニフェストをリセットします...\n");
122
+ }
123
+ await store.resetTable();
124
+ manifest = {
125
+ version: 1,
126
+ provider: active.provider,
127
+ model: active.model,
128
+ entries: {},
129
+ };
130
+ }
131
+ else if (hasExistingEntries && isModelChanged) {
132
+ isReset = true;
133
+ logger.info(`\n[プロバイダ / モデル変更を検知]`);
134
+ logger.info(` 前回: ${manifest.provider || "未記録"} (${manifest.model || "未記録"})`);
135
+ logger.info(` 今回: ${active.provider} (${active.model})`);
136
+ logger.info(` ベクトルの形式が異なるため、Vector DBを自動リセットして全件再インデックスします。\n`);
137
+ await store.resetTable();
138
+ manifest = {
139
+ version: 1,
140
+ provider: active.provider,
141
+ model: active.model,
142
+ entries: {},
143
+ };
144
+ }
145
+ else {
146
+ manifest.provider = active.provider;
147
+ manifest.model = active.model;
148
+ }
149
+ let targets = [];
150
+ try {
151
+ targets = await this.scanContentTargets(ctx.articlesDir, ctx.booksDir);
152
+ }
153
+ catch (err) {
154
+ logger.error(err instanceof Error ? err.message : String(err));
155
+ throw err;
156
+ }
157
+ const currentSlugs = new Set(targets.map((t) => t.slug));
158
+ // 削除されたコンテンツをDBから除去
159
+ for (const manifestSlug of Object.keys(manifest.entries)) {
160
+ if (!currentSlugs.has(manifestSlug)) {
161
+ logger.info(`[削除検知] ${manifestSlug} をDBから削除しています...`);
162
+ await store.deleteBySlug(manifestSlug);
163
+ delete manifest.entries[manifestSlug];
164
+ }
165
+ }
166
+ // 変更または未処理のファイルを抽出
167
+ const toProcess = [];
168
+ for (const target of targets) {
169
+ const content = await fs.readFile(target.filePath, "utf-8");
170
+ const currentHash = computeHash(content);
171
+ const prevEntry = manifest.entries[target.slug];
172
+ if (!prevEntry || prevEntry.fileHash !== currentHash || options.force) {
173
+ toProcess.push(target);
174
+ }
175
+ }
176
+ if (toProcess.length === 0) {
177
+ logger.info("全コンテンツがすでに最新状態です。更新の必要はありません。");
178
+ return {
179
+ totalFiles: targets.length,
180
+ processedArticles: 0,
181
+ totalChunks: 0,
182
+ isReset,
183
+ };
184
+ }
185
+ logger.info(`対象ファイル数: ${toProcess.length} 件 / 全 ${targets.length} 件`);
186
+ const allNewChunks = [];
187
+ for (const target of toProcess) {
188
+ if (target.itemType === "book" && target.bookSlug) {
189
+ const parsed = await parseBookChapterFile(target.filePath, target.bookSlug);
190
+ allNewChunks.push({
191
+ slug: target.slug,
192
+ fileHash: parsed.fileHash,
193
+ itemType: "book",
194
+ bookSlug: target.bookSlug,
195
+ chunks: parsed.chunks,
196
+ });
197
+ }
198
+ else {
199
+ const parsed = await parseArticleFile(target.filePath);
200
+ allNewChunks.push({
201
+ slug: target.slug,
202
+ fileHash: parsed.fileHash,
203
+ itemType: "article",
204
+ chunks: parsed.chunks,
205
+ });
206
+ }
207
+ }
208
+ const totalChunks = allNewChunks.reduce((acc, cur) => acc + cur.chunks.length, 0);
209
+ logger.info(`総チャンク数: ${totalChunks} 個`);
210
+ logger.info(`ベクトル埋め込みを生成中 (${active.provider} / ${active.model})...\n`);
211
+ let processedChunks = 0;
212
+ for (const item of allNewChunks) {
213
+ const typeLabel = item.itemType === "book" ? "[Book]" : "[Article]";
214
+ logger.write(`- ${typeLabel} ${item.slug} (${item.chunks.length} chunks)... `);
215
+ if (item.chunks.length === 0) {
216
+ logger.info("本文なし(スキップ)");
217
+ continue;
218
+ }
219
+ const textsToEmbed = item.chunks.map((c) => c.vectorText);
220
+ const vectors = await getEmbeddings(textsToEmbed);
221
+ for (let i = 0; i < item.chunks.length; i++) {
222
+ item.chunks[i].vector = vectors[i];
223
+ }
224
+ await store.deleteBySlug(item.slug);
225
+ await store.addChunks(item.chunks);
226
+ manifest.entries[item.slug] = {
227
+ fileHash: item.fileHash,
228
+ lastIndexed: new Date().toISOString(),
229
+ chunkIds: item.chunks.map((c) => c.id),
230
+ itemType: item.itemType,
231
+ bookSlug: item.bookSlug,
232
+ };
233
+ await this.saveManifest(ctx.manifestPath, manifest);
234
+ processedChunks += item.chunks.length;
235
+ logger.info(`完了 (${processedChunks}/${totalChunks})`);
236
+ }
237
+ logger.info("\nインデックス同期が正常に完了しました!");
238
+ return {
239
+ totalFiles: targets.length,
240
+ processedArticles: toProcess.length,
241
+ totalChunks,
242
+ isReset,
243
+ };
244
+ }
245
+ /**
246
+ * ファイル保存を監視して自動同期するウォッチモード
247
+ */
248
+ async watch(options = {}) {
249
+ const logger = options.logger ?? this.logger;
250
+ const ctx = getContext();
251
+ // 初回同期を実行
252
+ logger.info("[ウォッチモード起動] 初回インデックス同期を実行します...");
253
+ try {
254
+ await this.sync(options);
255
+ }
256
+ catch (err) {
257
+ logger.error("初回同期に失敗しました:", err);
258
+ }
259
+ logger.info("\n👀 ファイル変更を監視中... (終了するには Ctrl+C を押してください)");
260
+ let debounceTimer = null;
261
+ let isSyncing = false;
262
+ const triggerSync = (filename) => {
263
+ if (filename && !filename.endsWith(".md")) {
264
+ return;
265
+ }
266
+ if (debounceTimer) {
267
+ clearTimeout(debounceTimer);
268
+ }
269
+ debounceTimer = setTimeout(async () => {
270
+ if (isSyncing)
271
+ return;
272
+ isSyncing = true;
273
+ try {
274
+ logger.info(`\n[変更検知: ${filename || "ファイル"}] 差分同期を開始...`);
275
+ await this.sync(options);
276
+ logger.info("👀 ファイル変更を監視中...");
277
+ }
278
+ catch (err) {
279
+ logger.error("自動同期中にエラーが発生しました:", err);
280
+ }
281
+ finally {
282
+ isSyncing = false;
283
+ }
284
+ }, 1500);
285
+ };
286
+ // articles/ の監視
287
+ try {
288
+ fsWatch(ctx.articlesDir, { recursive: true }, (_, filename) => {
289
+ triggerSync(filename);
290
+ });
291
+ logger.info(`- 監視中: ${ctx.articlesDir}`);
292
+ }
293
+ catch {
294
+ // ディレクトリ未作成なら無視
295
+ }
296
+ // books/ の監視
297
+ try {
298
+ fsWatch(ctx.booksDir, { recursive: true }, (_, filename) => {
299
+ triggerSync(filename);
300
+ });
301
+ logger.info(`- 監視中: ${ctx.booksDir}`);
302
+ }
303
+ catch {
304
+ // ディレクトリ未作成なら無視
305
+ }
306
+ // プロセスを維持
307
+ await new Promise(() => { });
308
+ }
309
+ }
310
+ //# sourceMappingURL=sync-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-service.js","sourceRoot":"","sources":["../../src/services/sync-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAe,MAAM,cAAc,CAAC;AAqBtD,MAAM,OAAO,WAAW;IACd,MAAM,CAAS;IAEvB,YAAY,MAAe;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,SAAS,EAAE,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,YAAoB;QACrC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACrD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACrC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,YAAoB,EACpB,QAAsB;QAEtB,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,MAAM,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAC/E,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,kBAAkB,CAC9B,WAAmB,EACnB,QAAgB;QAEhB,MAAM,OAAO,GAAoB,EAAE,CAAC;QACpC,IAAI,cAAc,GAAG,KAAK,CAAC;QAE3B,eAAe;QACf,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YAC9C,cAAc,GAAG,IAAI,CAAC;YACtB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;oBACzC,OAAO,CAAC,IAAI,CAAC;wBACX,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC;wBACvC,IAAI;wBACJ,QAAQ,EAAE,SAAS;qBACpB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,sBAAsB;QACxB,CAAC;QAED,YAAY;QACZ,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YACxE,cAAc,GAAG,IAAI,CAAC;YACtB,KAAK,MAAM,SAAS,IAAI,WAAW,EAAE,CAAC;gBACpC,IAAI,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;oBAC5B,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC;oBAChC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;oBAClD,IAAI,CAAC;wBACH,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;wBACnD,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;4BAClC,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gCAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;gCAC5C,OAAO,CAAC,IAAI,CAAC;oCACX,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC;oCACxC,IAAI,EAAE,GAAG,QAAQ,IAAI,MAAM,EAAE;oCAC7B,QAAQ,EAAE,MAAM;oCAChB,QAAQ;iCACT,CAAC,CAAC;4BACL,CAAC;wBACH,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC;wBACP,oBAAoB;oBACtB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,mBAAmB;QACrB,CAAC;QAED,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CACb,mCAAmC,WAAW,YAAY,QAAQ,GAAG,CACtE,CAAC;QACJ,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAO,GAAgB,EAAE;QAClC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC;QAC7C,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;QAEhC,MAAM,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC/C,MAAM,CAAC,IAAI,CAAC,kBAAkB,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,kBAAkB,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC;QAEnD,IAAI,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,IAAI,kBAAkB,EAAE,CAAC;QACvC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QAEnB,MAAM,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAC5C,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,cAAc,CAAC,CAAC;QACtD,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC,OAAO,UAAU,KAAK,CAAC,CAAC;QAEpC,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,kBAAkB,EAAE,CAAC;QAC/C,MAAM,kBAAkB,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;QACpE,MAAM,mBAAmB,GAAG,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,UAAU,CAAC;QACnE,MAAM,cAAc,GAClB,CAAC,QAAQ,CAAC,KAAK;YACf,QAAQ,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ;YACrC,QAAQ,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK;YAC/B,mBAAmB,CAAC;QAEtB,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,IAAI,OAAO,CAAC,KAAK,IAAI,mBAAmB,EAAE,CAAC;YACzC,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,mBAAmB,EAAE,CAAC;gBACxB,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;gBAClC,MAAM,CAAC,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC;gBAClC,MAAM,CAAC,IAAI,CAAC,WAAW,UAAU,IAAI,CAAC,CAAC;gBACvC,MAAM,CAAC,IAAI,CACT,2DAA2D,CAC5D,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CACT,8CAA8C,CAC/C,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,CAAC,UAAU,EAAE,CAAC;YACzB,QAAQ,GAAG;gBACT,OAAO,EAAE,CAAC;gBACV,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,OAAO,EAAE,EAAE;aACZ,CAAC;QACJ,CAAC;aAAM,IAAI,kBAAkB,IAAI,cAAc,EAAE,CAAC;YAChD,OAAO,GAAG,IAAI,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;YACpC,MAAM,CAAC,IAAI,CACT,SAAS,QAAQ,CAAC,QAAQ,IAAI,KAAK,KAAK,QAAQ,CAAC,KAAK,IAAI,KAAK,GAAG,CACnE,CAAC;YACF,MAAM,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;YAC1D,MAAM,CAAC,IAAI,CACT,mDAAmD,CACpD,CAAC;YAEF,MAAM,KAAK,CAAC,UAAU,EAAE,CAAC;YACzB,QAAQ,GAAG;gBACT,OAAO,EAAE,CAAC;gBACV,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,OAAO,EAAE,EAAE;aACZ,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;YACpC,QAAQ,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QAChC,CAAC;QAED,IAAI,OAAO,GAAoB,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC/D,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAEzD,oBAAoB;QACpB,KAAK,MAAM,YAAY,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACzD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;gBACpC,MAAM,CAAC,IAAI,CAAC,UAAU,YAAY,kBAAkB,CAAC,CAAC;gBACtD,MAAM,KAAK,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;gBACvC,OAAO,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QAED,mBAAmB;QACnB,MAAM,SAAS,GAAoB,EAAE,CAAC;QACtC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC5D,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;YAEzC,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAChD,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,QAAQ,KAAK,WAAW,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBACtE,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;YAC7C,OAAO;gBACL,UAAU,EAAE,OAAO,CAAC,MAAM;gBAC1B,iBAAiB,EAAE,CAAC;gBACpB,WAAW,EAAE,CAAC;gBACd,OAAO;aACR,CAAC;QACJ,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,YAAY,SAAS,CAAC,MAAM,UAAU,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;QAEtE,MAAM,YAAY,GAMZ,EAAE,CAAC;QAET,KAAK,MAAM,MAAM,IAAI,SAAS,EAAE,CAAC;YAC/B,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;gBAClD,MAAM,MAAM,GAAG,MAAM,oBAAoB,CACvC,MAAM,CAAC,QAAQ,EACf,MAAM,CAAC,QAAQ,CAChB,CAAC;gBACF,YAAY,CAAC,IAAI,CAAC;oBAChB,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;oBACzB,QAAQ,EAAE,MAAM;oBAChB,QAAQ,EAAE,MAAM,CAAC,QAAQ;oBACzB,MAAM,EAAE,MAAM,CAAC,MAAM;iBACtB,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACvD,YAAY,CAAC,IAAI,CAAC;oBAChB,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;oBACzB,QAAQ,EAAE,SAAS;oBACnB,MAAM,EAAE,MAAM,CAAC,MAAM;iBACtB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,MAAM,WAAW,GAAG,YAAY,CAAC,MAAM,CACrC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,EACrC,CAAC,CACF,CAAC;QACF,MAAM,CAAC,IAAI,CAAC,WAAW,WAAW,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,IAAI,CACT,iBAAiB,MAAM,CAAC,QAAQ,MAAM,MAAM,CAAC,KAAK,QAAQ,CAC3D,CAAC;QAEF,IAAI,eAAe,GAAG,CAAC,CAAC;QACxB,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;YAChC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC;YACpE,MAAM,CAAC,KAAK,CACV,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,MAAM,cAAc,CACjE,CAAC;YAEF,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAC1B,SAAS;YACX,CAAC;YAED,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YAC1D,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC,CAAC;YAElD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5C,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACrC,CAAC;YAED,MAAM,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpC,MAAM,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAEnC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;gBAC5B,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACrC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtC,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;aACxB,CAAC;YACF,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;YAEpD,eAAe,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;YACtC,MAAM,CAAC,IAAI,CAAC,OAAO,eAAe,IAAI,WAAW,GAAG,CAAC,CAAC;QACxD,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QAErC,OAAO;YACL,UAAU,EAAE,OAAO,CAAC,MAAM;YAC1B,iBAAiB,EAAE,SAAS,CAAC,MAAM;YACnC,WAAW;YACX,OAAO;SACR,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK,CAAC,OAAO,GAAgB,EAAE;QACnC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC;QAC7C,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;QAEzB,UAAU;QACV,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAC/C,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;QACpC,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;QAE3D,IAAI,aAAa,GAA0B,IAAI,CAAC;QAChD,IAAI,SAAS,GAAG,KAAK,CAAC;QAEtB,MAAM,WAAW,GAAG,CAAC,QAAwB,EAAE,EAAE;YAC/C,IAAI,QAAQ,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1C,OAAO;YACT,CAAC;YAED,IAAI,aAAa,EAAE,CAAC;gBAClB,YAAY,CAAC,aAAa,CAAC,CAAC;YAC9B,CAAC;YAED,aAAa,GAAG,UAAU,CAAC,KAAK,IAAI,EAAE;gBACpC,IAAI,SAAS;oBAAE,OAAO;gBACtB,SAAS,GAAG,IAAI,CAAC;gBACjB,IAAI,CAAC;oBACH,MAAM,CAAC,IAAI,CAAC,YAAY,QAAQ,IAAI,MAAM,cAAc,CAAC,CAAC;oBAC1D,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBACzB,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;gBAClC,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;gBACzC,CAAC;wBAAS,CAAC;oBACT,SAAS,GAAG,KAAK,CAAC;gBACpB,CAAC;YACH,CAAC,EAAE,IAAI,CAAC,CAAC;QACX,CAAC,CAAC;QAEF,gBAAgB;QAChB,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE;gBAC5D,WAAW,CAAC,QAAQ,CAAC,CAAC;YACxB,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB;QAClB,CAAC;QAED,aAAa;QACb,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE;gBACzD,WAAW,CAAC,QAAQ,CAAC,CAAC;YACxB,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;QACxC,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB;QAClB,CAAC;QAED,UAAU;QACV,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC9B,CAAC;CACF"}
@@ -0,0 +1,35 @@
1
+ import { type Table } from "@lancedb/lancedb";
2
+ import type { ArticleChunk, SearchResult } from "./types.js";
3
+ export interface DBRecord {
4
+ id: string;
5
+ slug: string;
6
+ title: string;
7
+ topics: string;
8
+ heading: string;
9
+ text: string;
10
+ url: string;
11
+ contentHash: string;
12
+ vector: number[];
13
+ itemType: string;
14
+ bookSlug: string;
15
+ [key: string]: unknown;
16
+ }
17
+ export declare class ArticleVectorStore {
18
+ private db;
19
+ private table;
20
+ private getDb;
21
+ init(): Promise<void>;
22
+ resetTable(): Promise<void>;
23
+ getVectorDimension(): Promise<number | null>;
24
+ getTable(): Promise<Table | null>;
25
+ private getOrCreateTable;
26
+ addChunks(chunks: ArticleChunk[]): Promise<void>;
27
+ deleteBySlug(slug: string): Promise<void>;
28
+ search(queryVector: number[], options?: {
29
+ limit?: number;
30
+ topic?: string;
31
+ }): Promise<SearchResult[]>;
32
+ getAllTopics(): Promise<Record<string, number>>;
33
+ getArticleChunks(slug: string): Promise<SearchResult[]>;
34
+ }
35
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AACA,OAAO,EAA4B,KAAK,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAExE,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI7D,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAgDD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,EAAE,CAA2B;IACrC,OAAO,CAAC,KAAK,CAAsB;YAErB,KAAK;IASb,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAE1B;IAEK,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAOhC;IAEK,kBAAkB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAcjD;IAEK,QAAQ,IAAI,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAWtC;YAEa,gBAAgB;IAYxB,SAAS,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAUrD;IAEK,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS9C;IAEK,MAAM,CACV,WAAW,EAAE,MAAM,EAAE,EACrB,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAC/C,OAAO,CAAC,YAAY,EAAE,CAAC,CAqBzB;IAEK,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAyBpD;IAEK,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAQ5D;CACF"}
package/dist/store.js ADDED
@@ -0,0 +1,180 @@
1
+ import fs from "node:fs/promises";
2
+ import { connect } from "@lancedb/lancedb";
3
+ import { getContext } from "./config.js";
4
+ const TABLE_NAME = "article_chunks";
5
+ function chunkToRecord(chunk) {
6
+ if (!chunk.vector) {
7
+ throw new Error(`Chunk ${chunk.id} にベクトルが含まれていません`);
8
+ }
9
+ return {
10
+ id: chunk.id,
11
+ slug: chunk.slug,
12
+ title: chunk.title,
13
+ topics: chunk.topics.join(", "),
14
+ heading: chunk.heading,
15
+ text: chunk.text,
16
+ url: chunk.url,
17
+ contentHash: chunk.contentHash,
18
+ vector: chunk.vector,
19
+ itemType: chunk.itemType || "article",
20
+ bookSlug: chunk.bookSlug || "",
21
+ };
22
+ }
23
+ function rowToSearchResult(row, score) {
24
+ const topicsStr = row.topics || "";
25
+ const topics = topicsStr
26
+ .split(",")
27
+ .map((s) => s.trim())
28
+ .filter(Boolean);
29
+ const itemType = row.itemType || "article";
30
+ const bookSlug = row.bookSlug || undefined;
31
+ return {
32
+ id: String(row.id),
33
+ slug: String(row.slug),
34
+ title: String(row.title),
35
+ topics,
36
+ heading: String(row.heading),
37
+ text: String(row.text),
38
+ url: String(row.url),
39
+ score,
40
+ itemType,
41
+ bookSlug: bookSlug || undefined,
42
+ };
43
+ }
44
+ export class ArticleVectorStore {
45
+ db = null;
46
+ table = null;
47
+ async getDb() {
48
+ if (!this.db) {
49
+ const ctx = getContext();
50
+ await fs.mkdir(ctx.vectorDbDir, { recursive: true });
51
+ this.db = await connect(ctx.vectorDbDir);
52
+ }
53
+ return this.db;
54
+ }
55
+ async init() {
56
+ await this.getTable();
57
+ }
58
+ async resetTable() {
59
+ const db = await this.getDb();
60
+ const tables = await db.tableNames();
61
+ if (tables.includes(TABLE_NAME)) {
62
+ await db.dropTable(TABLE_NAME);
63
+ }
64
+ this.table = null;
65
+ }
66
+ async getVectorDimension() {
67
+ const table = await this.getTable();
68
+ if (!table)
69
+ return null;
70
+ try {
71
+ const rows = await table.query().limit(1).toArray();
72
+ const vec = rows[0]?.vector;
73
+ if (typeof vec?.length === "number") {
74
+ return vec.length;
75
+ }
76
+ }
77
+ catch {
78
+ // テーブルが空などの場合はnull
79
+ }
80
+ return null;
81
+ }
82
+ async getTable() {
83
+ if (this.table) {
84
+ return this.table;
85
+ }
86
+ const db = await this.getDb();
87
+ const tables = await db.tableNames();
88
+ if (tables.includes(TABLE_NAME)) {
89
+ this.table = await db.openTable(TABLE_NAME);
90
+ return this.table;
91
+ }
92
+ return null;
93
+ }
94
+ async getOrCreateTable(sampleData) {
95
+ const db = await this.getDb();
96
+ const tables = await db.tableNames();
97
+ if (tables.includes(TABLE_NAME)) {
98
+ this.table = await db.openTable(TABLE_NAME);
99
+ }
100
+ else {
101
+ this.table = await db.createTable(TABLE_NAME, sampleData);
102
+ }
103
+ return this.table;
104
+ }
105
+ async addChunks(chunks) {
106
+ if (chunks.length === 0)
107
+ return;
108
+ const records = chunks.map(chunkToRecord);
109
+ const table = await this.getTable();
110
+ if (!table) {
111
+ await this.getOrCreateTable(records);
112
+ }
113
+ else {
114
+ await table.add(records);
115
+ }
116
+ }
117
+ async deleteBySlug(slug) {
118
+ const table = await this.getTable();
119
+ if (!table)
120
+ return;
121
+ try {
122
+ await table.delete(`slug = '${slug}'`);
123
+ }
124
+ catch {
125
+ // 削除エラーは許容
126
+ }
127
+ }
128
+ async search(queryVector, options = {}) {
129
+ const table = await this.getTable();
130
+ if (!table)
131
+ return [];
132
+ const limit = options.limit || 5;
133
+ let query = table
134
+ .vectorSearch(queryVector)
135
+ .distanceType("cosine")
136
+ .limit(limit);
137
+ if (options.topic) {
138
+ query = query.where(`topics LIKE '%${options.topic}%'`);
139
+ }
140
+ const rawResults = await query.toArray();
141
+ return rawResults.map((row) => {
142
+ const distance = row._distance ?? 0;
143
+ const score = Math.max(0, 1 - distance);
144
+ return rowToSearchResult(row, score);
145
+ });
146
+ }
147
+ async getAllTopics() {
148
+ const table = await this.getTable();
149
+ if (!table)
150
+ return {};
151
+ const rows = await table.query().select(["topics", "slug"]).toArray();
152
+ const topicCounts = {};
153
+ for (const row of rows) {
154
+ const topicsStr = row.topics || "";
155
+ const slug = String(row.slug);
156
+ const topics = topicsStr
157
+ .split(",")
158
+ .map((s) => s.trim())
159
+ .filter(Boolean);
160
+ for (const t of topics) {
161
+ if (!topicCounts[t])
162
+ topicCounts[t] = new Set();
163
+ topicCounts[t].add(slug);
164
+ }
165
+ }
166
+ const result = {};
167
+ for (const [topic, slugs] of Object.entries(topicCounts)) {
168
+ result[topic] = slugs.size;
169
+ }
170
+ return result;
171
+ }
172
+ async getArticleChunks(slug) {
173
+ const table = await this.getTable();
174
+ if (!table)
175
+ return [];
176
+ const rows = await table.query().where(`slug = '${slug}'`).toArray();
177
+ return rows.map((row) => rowToSearchResult(row, 1.0));
178
+ }
179
+ }
180
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ export interface ArticleFrontmatter {
2
+ title: string;
3
+ emoji?: string;
4
+ type?: "tech" | "idea";
5
+ topics?: string[];
6
+ published?: boolean;
7
+ [key: string]: unknown;
8
+ }
9
+ export type ItemType = "article" | "book";
10
+ export interface ArticleChunk {
11
+ id: string;
12
+ slug: string;
13
+ title: string;
14
+ topics: string[];
15
+ heading: string;
16
+ text: string;
17
+ vectorText: string;
18
+ url: string;
19
+ contentHash: string;
20
+ vector?: number[];
21
+ itemType?: ItemType;
22
+ bookSlug?: string;
23
+ }
24
+ export interface ManifestEntry {
25
+ fileHash: string;
26
+ lastIndexed: string;
27
+ chunkIds: string[];
28
+ itemType?: ItemType;
29
+ bookSlug?: string;
30
+ }
31
+ export interface SyncManifest {
32
+ version: number;
33
+ provider?: string;
34
+ model?: string;
35
+ entries: Record<string, ManifestEntry>;
36
+ }
37
+ export interface SearchResult {
38
+ id: string;
39
+ slug: string;
40
+ title: string;
41
+ topics: string[];
42
+ heading: string;
43
+ text: string;
44
+ url: string;
45
+ score: number;
46
+ itemType?: ItemType;
47
+ bookSlug?: string;
48
+ }
49
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAE1C,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}