@nahisaho/katashiro-rag 2.0.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.
- package/LICENSE +21 -0
- package/dist/RAGEngine.d.ts +58 -0
- package/dist/RAGEngine.d.ts.map +1 -0
- package/dist/RAGEngine.js +97 -0
- package/dist/RAGEngine.js.map +1 -0
- package/dist/RAGPipeline.d.ts +162 -0
- package/dist/RAGPipeline.d.ts.map +1 -0
- package/dist/RAGPipeline.js +222 -0
- package/dist/RAGPipeline.js.map +1 -0
- package/dist/Retriever.d.ts +49 -0
- package/dist/Retriever.d.ts.map +1 -0
- package/dist/Retriever.js +96 -0
- package/dist/Retriever.js.map +1 -0
- package/dist/chunking/DocumentChunker.d.ts +47 -0
- package/dist/chunking/DocumentChunker.d.ts.map +1 -0
- package/dist/chunking/DocumentChunker.js +171 -0
- package/dist/chunking/DocumentChunker.js.map +1 -0
- package/dist/chunking/index.d.ts +5 -0
- package/dist/chunking/index.d.ts.map +1 -0
- package/dist/chunking/index.js +5 -0
- package/dist/chunking/index.js.map +1 -0
- package/dist/embedding/AzureOpenAIEmbeddingProvider.d.ts +63 -0
- package/dist/embedding/AzureOpenAIEmbeddingProvider.d.ts.map +1 -0
- package/dist/embedding/AzureOpenAIEmbeddingProvider.js +133 -0
- package/dist/embedding/AzureOpenAIEmbeddingProvider.js.map +1 -0
- package/dist/embedding/BaseEmbeddingProvider.d.ts +43 -0
- package/dist/embedding/BaseEmbeddingProvider.d.ts.map +1 -0
- package/dist/embedding/BaseEmbeddingProvider.js +98 -0
- package/dist/embedding/BaseEmbeddingProvider.js.map +1 -0
- package/dist/embedding/EmbeddingFactory.d.ts +75 -0
- package/dist/embedding/EmbeddingFactory.d.ts.map +1 -0
- package/dist/embedding/EmbeddingFactory.js +153 -0
- package/dist/embedding/EmbeddingFactory.js.map +1 -0
- package/dist/embedding/EmbeddingManager.d.ts +41 -0
- package/dist/embedding/EmbeddingManager.d.ts.map +1 -0
- package/dist/embedding/EmbeddingManager.js +93 -0
- package/dist/embedding/EmbeddingManager.js.map +1 -0
- package/dist/embedding/MockEmbeddingProvider.d.ts +54 -0
- package/dist/embedding/MockEmbeddingProvider.d.ts.map +1 -0
- package/dist/embedding/MockEmbeddingProvider.js +91 -0
- package/dist/embedding/MockEmbeddingProvider.js.map +1 -0
- package/dist/embedding/OllamaEmbeddingProvider.d.ts +69 -0
- package/dist/embedding/OllamaEmbeddingProvider.d.ts.map +1 -0
- package/dist/embedding/OllamaEmbeddingProvider.js +136 -0
- package/dist/embedding/OllamaEmbeddingProvider.js.map +1 -0
- package/dist/embedding/OpenAIEmbeddingProvider.d.ts +83 -0
- package/dist/embedding/OpenAIEmbeddingProvider.d.ts.map +1 -0
- package/dist/embedding/OpenAIEmbeddingProvider.js +150 -0
- package/dist/embedding/OpenAIEmbeddingProvider.js.map +1 -0
- package/dist/embedding/index.d.ts +16 -0
- package/dist/embedding/index.d.ts.map +1 -0
- package/dist/embedding/index.js +15 -0
- package/dist/embedding/index.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/reranking/LLMReranker.d.ts +147 -0
- package/dist/reranking/LLMReranker.d.ts.map +1 -0
- package/dist/reranking/LLMReranker.js +262 -0
- package/dist/reranking/LLMReranker.js.map +1 -0
- package/dist/reranking/index.d.ts +7 -0
- package/dist/reranking/index.d.ts.map +1 -0
- package/dist/reranking/index.js +7 -0
- package/dist/reranking/index.js.map +1 -0
- package/dist/types.d.ts +144 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/vectordb/FileVectorStore.d.ts +93 -0
- package/dist/vectordb/FileVectorStore.d.ts.map +1 -0
- package/dist/vectordb/FileVectorStore.js +218 -0
- package/dist/vectordb/FileVectorStore.js.map +1 -0
- package/dist/vectordb/InMemoryVectorStore.d.ts +48 -0
- package/dist/vectordb/InMemoryVectorStore.d.ts.map +1 -0
- package/dist/vectordb/InMemoryVectorStore.js +86 -0
- package/dist/vectordb/InMemoryVectorStore.js.map +1 -0
- package/dist/vectordb/index.d.ts +8 -0
- package/dist/vectordb/index.d.ts.map +1 -0
- package/dist/vectordb/index.js +6 -0
- package/dist/vectordb/index.js.map +1 -0
- package/package.json +37 -0
- package/src/RAGEngine.ts +127 -0
- package/src/RAGPipeline.ts +357 -0
- package/src/Retriever.ts +121 -0
- package/src/chunking/DocumentChunker.ts +207 -0
- package/src/chunking/index.ts +5 -0
- package/src/embedding/AzureOpenAIEmbeddingProvider.ts +208 -0
- package/src/embedding/BaseEmbeddingProvider.ts +133 -0
- package/src/embedding/EmbeddingFactory.ts +225 -0
- package/src/embedding/EmbeddingManager.ts +110 -0
- package/src/embedding/MockEmbeddingProvider.ts +123 -0
- package/src/embedding/OllamaEmbeddingProvider.ts +197 -0
- package/src/embedding/OpenAIEmbeddingProvider.ts +226 -0
- package/src/embedding/index.ts +33 -0
- package/src/index.ts +55 -0
- package/src/reranking/LLMReranker.ts +401 -0
- package/src/reranking/index.ts +15 -0
- package/src/types.ts +157 -0
- package/src/vectordb/FileVectorStore.ts +289 -0
- package/src/vectordb/InMemoryVectorStore.ts +121 -0
- package/src/vectordb/index.ts +9 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-based Vector Store
|
|
3
|
+
*
|
|
4
|
+
* @requirement REQ-RAG-102
|
|
5
|
+
* @design DES-KATASHIRO-003-RAG §3.3
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Chunk, SearchResult, Vector, VectorStore } from '../types.js';
|
|
9
|
+
import * as fs from 'node:fs';
|
|
10
|
+
import * as path from 'node:path';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* FileVectorStoreの設定
|
|
14
|
+
*/
|
|
15
|
+
export interface FileVectorStoreConfig {
|
|
16
|
+
/** 保存先ファイルパス */
|
|
17
|
+
filePath: string;
|
|
18
|
+
/** 類似度しきい値(デフォルト: 0.7) */
|
|
19
|
+
similarityThreshold?: number;
|
|
20
|
+
/** 自動保存(デフォルト: true) */
|
|
21
|
+
autoSave?: boolean;
|
|
22
|
+
/** 保存間隔(ミリ秒、デフォルト: 1000) */
|
|
23
|
+
saveIntervalMs?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 格納されたベクトルエントリ
|
|
28
|
+
*/
|
|
29
|
+
interface StoredEntry {
|
|
30
|
+
chunk: Chunk;
|
|
31
|
+
vector: Vector;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* ファイル保存用データ構造
|
|
36
|
+
*/
|
|
37
|
+
interface PersistedData {
|
|
38
|
+
version: string;
|
|
39
|
+
createdAt: string;
|
|
40
|
+
updatedAt: string;
|
|
41
|
+
entries: Array<{
|
|
42
|
+
chunkId: string;
|
|
43
|
+
chunk: Chunk;
|
|
44
|
+
vector: Vector;
|
|
45
|
+
}>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* ファイルベースのベクトルストア
|
|
50
|
+
* データをJSONファイルに永続化
|
|
51
|
+
*/
|
|
52
|
+
export class FileVectorStore implements VectorStore {
|
|
53
|
+
readonly name = 'file';
|
|
54
|
+
|
|
55
|
+
private entries: Map<string, StoredEntry> = new Map();
|
|
56
|
+
private filePath: string;
|
|
57
|
+
private similarityThreshold: number;
|
|
58
|
+
private autoSave: boolean;
|
|
59
|
+
private saveIntervalMs: number;
|
|
60
|
+
private isDirty = false;
|
|
61
|
+
private saveTimer: ReturnType<typeof setTimeout> | null = null;
|
|
62
|
+
private createdAt: string;
|
|
63
|
+
private isInitialized = false;
|
|
64
|
+
|
|
65
|
+
constructor(config: FileVectorStoreConfig) {
|
|
66
|
+
this.filePath = path.resolve(config.filePath);
|
|
67
|
+
this.similarityThreshold = config.similarityThreshold ?? 0.7;
|
|
68
|
+
this.autoSave = config.autoSave ?? true;
|
|
69
|
+
this.saveIntervalMs = config.saveIntervalMs ?? 1000;
|
|
70
|
+
this.createdAt = new Date().toISOString();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 格納エントリ数を取得
|
|
75
|
+
*/
|
|
76
|
+
get size(): number {
|
|
77
|
+
return this.entries.size;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* ストアを初期化(ファイルから読み込み)
|
|
82
|
+
*/
|
|
83
|
+
async init(): Promise<void> {
|
|
84
|
+
if (this.isInitialized) return;
|
|
85
|
+
|
|
86
|
+
if (fs.existsSync(this.filePath)) {
|
|
87
|
+
try {
|
|
88
|
+
const data = await fs.promises.readFile(this.filePath, 'utf-8');
|
|
89
|
+
const parsed = JSON.parse(data) as PersistedData;
|
|
90
|
+
|
|
91
|
+
// データを読み込み
|
|
92
|
+
for (const entry of parsed.entries) {
|
|
93
|
+
this.entries.set(entry.chunkId, {
|
|
94
|
+
chunk: entry.chunk,
|
|
95
|
+
vector: entry.vector,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (parsed.createdAt) {
|
|
100
|
+
this.createdAt = parsed.createdAt;
|
|
101
|
+
}
|
|
102
|
+
} catch (error) {
|
|
103
|
+
// ファイルが壊れている場合は空で開始
|
|
104
|
+
console.warn(`Failed to load vector store from ${this.filePath}:`, error);
|
|
105
|
+
this.entries.clear();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
this.isInitialized = true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async add(chunk: Chunk, vector: Vector): Promise<void> {
|
|
113
|
+
await this.ensureInitialized();
|
|
114
|
+
this.entries.set(chunk.id, { chunk, vector });
|
|
115
|
+
this.markDirty();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async addBatch(items: Array<{ chunk: Chunk; vector: Vector }>): Promise<void> {
|
|
119
|
+
await this.ensureInitialized();
|
|
120
|
+
for (const item of items) {
|
|
121
|
+
this.entries.set(item.chunk.id, { chunk: item.chunk, vector: item.vector });
|
|
122
|
+
}
|
|
123
|
+
this.markDirty();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async search(vector: Vector, topK: number): Promise<SearchResult[]> {
|
|
127
|
+
await this.ensureInitialized();
|
|
128
|
+
const results: Array<{ entry: StoredEntry; similarity: number }> = [];
|
|
129
|
+
|
|
130
|
+
for (const entry of this.entries.values()) {
|
|
131
|
+
const similarity = this.cosineSimilarity(vector, entry.vector);
|
|
132
|
+
|
|
133
|
+
if (similarity >= this.similarityThreshold) {
|
|
134
|
+
results.push({ entry, similarity });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// スコア降順でソート
|
|
139
|
+
results.sort((a, b) => b.similarity - a.similarity);
|
|
140
|
+
|
|
141
|
+
// topKに制限
|
|
142
|
+
return results.slice(0, topK).map(({ entry, similarity }) => ({
|
|
143
|
+
chunk: entry.chunk,
|
|
144
|
+
score: similarity,
|
|
145
|
+
}));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async delete(chunkId: string): Promise<boolean> {
|
|
149
|
+
await this.ensureInitialized();
|
|
150
|
+
const result = this.entries.delete(chunkId);
|
|
151
|
+
if (result) {
|
|
152
|
+
this.markDirty();
|
|
153
|
+
}
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* ストアをクリア
|
|
159
|
+
*/
|
|
160
|
+
async clear(): Promise<void> {
|
|
161
|
+
await this.ensureInitialized();
|
|
162
|
+
this.entries.clear();
|
|
163
|
+
this.markDirty();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* 指定IDのチャンクが存在するか確認
|
|
168
|
+
*/
|
|
169
|
+
async has(chunkId: string): Promise<boolean> {
|
|
170
|
+
await this.ensureInitialized();
|
|
171
|
+
return this.entries.has(chunkId);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* 即座にファイルに保存
|
|
176
|
+
*/
|
|
177
|
+
async save(): Promise<void> {
|
|
178
|
+
await this.ensureInitialized();
|
|
179
|
+
|
|
180
|
+
// ディレクトリが存在しない場合は作成
|
|
181
|
+
const dir = path.dirname(this.filePath);
|
|
182
|
+
if (!fs.existsSync(dir)) {
|
|
183
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const data: PersistedData = {
|
|
187
|
+
version: '1.0.0',
|
|
188
|
+
createdAt: this.createdAt,
|
|
189
|
+
updatedAt: new Date().toISOString(),
|
|
190
|
+
entries: Array.from(this.entries.entries()).map(([chunkId, entry]) => ({
|
|
191
|
+
chunkId,
|
|
192
|
+
chunk: entry.chunk,
|
|
193
|
+
vector: entry.vector,
|
|
194
|
+
})),
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
await fs.promises.writeFile(this.filePath, JSON.stringify(data, null, 2), 'utf-8');
|
|
198
|
+
this.isDirty = false;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* 未保存の変更があるか確認
|
|
203
|
+
*/
|
|
204
|
+
get dirty(): boolean {
|
|
205
|
+
return this.isDirty;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* ストアを閉じる(保留中の保存を実行)
|
|
210
|
+
*/
|
|
211
|
+
async close(): Promise<void> {
|
|
212
|
+
if (this.saveTimer) {
|
|
213
|
+
clearTimeout(this.saveTimer);
|
|
214
|
+
this.saveTimer = null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (this.isDirty) {
|
|
218
|
+
await this.save();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* ファイルパスを取得
|
|
224
|
+
*/
|
|
225
|
+
getFilePath(): string {
|
|
226
|
+
return this.filePath;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* 初期化を確認
|
|
231
|
+
*/
|
|
232
|
+
private async ensureInitialized(): Promise<void> {
|
|
233
|
+
if (!this.isInitialized) {
|
|
234
|
+
await this.init();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* 変更をマーク
|
|
240
|
+
*/
|
|
241
|
+
private markDirty(): void {
|
|
242
|
+
this.isDirty = true;
|
|
243
|
+
|
|
244
|
+
if (this.autoSave) {
|
|
245
|
+
this.scheduleSave();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* 保存をスケジュール
|
|
251
|
+
*/
|
|
252
|
+
private scheduleSave(): void {
|
|
253
|
+
if (this.saveTimer) {
|
|
254
|
+
clearTimeout(this.saveTimer);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
this.saveTimer = setTimeout(() => {
|
|
258
|
+
this.save().catch((err) => {
|
|
259
|
+
console.error('Failed to auto-save vector store:', err);
|
|
260
|
+
});
|
|
261
|
+
}, this.saveIntervalMs);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* コサイン類似度を計算
|
|
266
|
+
*/
|
|
267
|
+
private cosineSimilarity(a: Vector, b: Vector): number {
|
|
268
|
+
if (a.length !== b.length) {
|
|
269
|
+
throw new Error(`Vector dimension mismatch: ${a.length} vs ${b.length}`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
let dotProduct = 0;
|
|
273
|
+
let normA = 0;
|
|
274
|
+
let normB = 0;
|
|
275
|
+
|
|
276
|
+
for (let i = 0; i < a.length; i++) {
|
|
277
|
+
const valA = a[i] ?? 0;
|
|
278
|
+
const valB = b[i] ?? 0;
|
|
279
|
+
dotProduct += valA * valB;
|
|
280
|
+
normA += valA * valA;
|
|
281
|
+
normB += valB * valB;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const denominator = Math.sqrt(normA) * Math.sqrt(normB);
|
|
285
|
+
if (denominator === 0) return 0;
|
|
286
|
+
|
|
287
|
+
return dotProduct / denominator;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-Memory Vector Store
|
|
3
|
+
*
|
|
4
|
+
* @requirement REQ-RAG-002
|
|
5
|
+
* @design DES-KATASHIRO-003-RAG §3.2
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Chunk, SearchResult, Vector, VectorStore } from '../types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* インメモリベクトルストアの設定
|
|
12
|
+
*/
|
|
13
|
+
export interface InMemoryVectorStoreConfig {
|
|
14
|
+
/** 類似度しきい値(デフォルト: 0.7) */
|
|
15
|
+
similarityThreshold?: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 格納されたベクトルエントリ
|
|
20
|
+
*/
|
|
21
|
+
interface StoredEntry {
|
|
22
|
+
chunk: Chunk;
|
|
23
|
+
vector: Vector;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* インメモリベクトルストア
|
|
28
|
+
* テスト用およびプロトタイピング用
|
|
29
|
+
*/
|
|
30
|
+
export class InMemoryVectorStore implements VectorStore {
|
|
31
|
+
readonly name = 'in-memory';
|
|
32
|
+
|
|
33
|
+
private entries: Map<string, StoredEntry> = new Map();
|
|
34
|
+
private similarityThreshold: number;
|
|
35
|
+
|
|
36
|
+
constructor(config: InMemoryVectorStoreConfig = {}) {
|
|
37
|
+
this.similarityThreshold = config.similarityThreshold ?? 0.7;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 格納エントリ数を取得
|
|
42
|
+
*/
|
|
43
|
+
get size(): number {
|
|
44
|
+
return this.entries.size;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async add(chunk: Chunk, vector: Vector): Promise<void> {
|
|
48
|
+
this.entries.set(chunk.id, { chunk, vector });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async addBatch(items: Array<{ chunk: Chunk; vector: Vector }>): Promise<void> {
|
|
52
|
+
for (const item of items) {
|
|
53
|
+
this.entries.set(item.chunk.id, { chunk: item.chunk, vector: item.vector });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async search(vector: Vector, topK: number): Promise<SearchResult[]> {
|
|
58
|
+
const results: Array<{ entry: StoredEntry; similarity: number }> = [];
|
|
59
|
+
|
|
60
|
+
for (const entry of this.entries.values()) {
|
|
61
|
+
const similarity = this.cosineSimilarity(vector, entry.vector);
|
|
62
|
+
|
|
63
|
+
if (similarity >= this.similarityThreshold) {
|
|
64
|
+
results.push({ entry, similarity });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// スコア降順でソート
|
|
69
|
+
results.sort((a, b) => b.similarity - a.similarity);
|
|
70
|
+
|
|
71
|
+
// topKに制限
|
|
72
|
+
return results.slice(0, topK).map(({ entry, similarity }) => ({
|
|
73
|
+
chunk: entry.chunk,
|
|
74
|
+
score: similarity,
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async delete(chunkId: string): Promise<boolean> {
|
|
79
|
+
return this.entries.delete(chunkId);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* ストアをクリア
|
|
84
|
+
*/
|
|
85
|
+
clear(): void {
|
|
86
|
+
this.entries.clear();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 指定IDのチャンクが存在するか確認
|
|
91
|
+
*/
|
|
92
|
+
has(chunkId: string): boolean {
|
|
93
|
+
return this.entries.has(chunkId);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* コサイン類似度を計算
|
|
98
|
+
*/
|
|
99
|
+
private cosineSimilarity(a: Vector, b: Vector): number {
|
|
100
|
+
if (a.length !== b.length) {
|
|
101
|
+
throw new Error(`Vector dimension mismatch: ${a.length} vs ${b.length}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let dotProduct = 0;
|
|
105
|
+
let normA = 0;
|
|
106
|
+
let normB = 0;
|
|
107
|
+
|
|
108
|
+
for (let i = 0; i < a.length; i++) {
|
|
109
|
+
const valA = a[i] ?? 0;
|
|
110
|
+
const valB = b[i] ?? 0;
|
|
111
|
+
dotProduct += valA * valB;
|
|
112
|
+
normA += valA * valA;
|
|
113
|
+
normB += valB * valB;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const denominator = Math.sqrt(normA) * Math.sqrt(normB);
|
|
117
|
+
if (denominator === 0) return 0;
|
|
118
|
+
|
|
119
|
+
return dotProduct / denominator;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vector DB module exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { InMemoryVectorStore } from './InMemoryVectorStore.js';
|
|
6
|
+
export type { InMemoryVectorStoreConfig } from './InMemoryVectorStore.js';
|
|
7
|
+
|
|
8
|
+
export { FileVectorStore } from './FileVectorStore.js';
|
|
9
|
+
export type { FileVectorStoreConfig } from './FileVectorStore.js';
|