@pleaseai/context-please-core 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.
- package/LICENSE +24 -0
- package/README.md +287 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/context.d.ts +276 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +1072 -0
- package/dist/context.js.map +1 -0
- package/dist/embedding/base-embedding.d.ts +51 -0
- package/dist/embedding/base-embedding.d.ts.map +1 -0
- package/dist/embedding/base-embedding.js +36 -0
- package/dist/embedding/base-embedding.js.map +1 -0
- package/dist/embedding/gemini-embedding.d.ts +53 -0
- package/dist/embedding/gemini-embedding.d.ts.map +1 -0
- package/dist/embedding/gemini-embedding.js +152 -0
- package/dist/embedding/gemini-embedding.js.map +1 -0
- package/dist/embedding/index.d.ts +6 -0
- package/dist/embedding/index.d.ts.map +1 -0
- package/dist/embedding/index.js +24 -0
- package/dist/embedding/index.js.map +1 -0
- package/dist/embedding/ollama-embedding.d.ts +55 -0
- package/dist/embedding/ollama-embedding.d.ts.map +1 -0
- package/dist/embedding/ollama-embedding.js +192 -0
- package/dist/embedding/ollama-embedding.js.map +1 -0
- package/dist/embedding/openai-embedding.d.ts +36 -0
- package/dist/embedding/openai-embedding.d.ts.map +1 -0
- package/dist/embedding/openai-embedding.js +159 -0
- package/dist/embedding/openai-embedding.js.map +1 -0
- package/dist/embedding/voyageai-embedding.d.ts +44 -0
- package/dist/embedding/voyageai-embedding.d.ts.map +1 -0
- package/dist/embedding/voyageai-embedding.js +227 -0
- package/dist/embedding/voyageai-embedding.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/splitter/ast-splitter.d.ts +22 -0
- package/dist/splitter/ast-splitter.d.ts.map +1 -0
- package/dist/splitter/ast-splitter.js +234 -0
- package/dist/splitter/ast-splitter.js.map +1 -0
- package/dist/splitter/index.d.ts +41 -0
- package/dist/splitter/index.d.ts.map +1 -0
- package/dist/splitter/index.js +27 -0
- package/dist/splitter/index.js.map +1 -0
- package/dist/splitter/langchain-splitter.d.ts +13 -0
- package/dist/splitter/langchain-splitter.d.ts.map +1 -0
- package/dist/splitter/langchain-splitter.js +118 -0
- package/dist/splitter/langchain-splitter.js.map +1 -0
- package/dist/sync/merkle.d.ts +26 -0
- package/dist/sync/merkle.d.ts.map +1 -0
- package/dist/sync/merkle.js +112 -0
- package/dist/sync/merkle.js.map +1 -0
- package/dist/sync/synchronizer.d.ts +30 -0
- package/dist/sync/synchronizer.d.ts.map +1 -0
- package/dist/sync/synchronizer.js +339 -0
- package/dist/sync/synchronizer.js.map +1 -0
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/env-manager.d.ts +19 -0
- package/dist/utils/env-manager.d.ts.map +1 -0
- package/dist/utils/env-manager.js +125 -0
- package/dist/utils/env-manager.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/vectordb/base/base-vector-database.d.ts +58 -0
- package/dist/vectordb/base/base-vector-database.d.ts.map +1 -0
- package/dist/vectordb/base/base-vector-database.js +32 -0
- package/dist/vectordb/base/base-vector-database.js.map +1 -0
- package/dist/vectordb/factory.d.ts +80 -0
- package/dist/vectordb/factory.d.ts.map +1 -0
- package/dist/vectordb/factory.js +89 -0
- package/dist/vectordb/factory.js.map +1 -0
- package/dist/vectordb/index.d.ts +12 -0
- package/dist/vectordb/index.d.ts.map +1 -0
- package/dist/vectordb/index.js +27 -0
- package/dist/vectordb/index.js.map +1 -0
- package/dist/vectordb/milvus-restful-vectordb.d.ts +75 -0
- package/dist/vectordb/milvus-restful-vectordb.d.ts.map +1 -0
- package/dist/vectordb/milvus-restful-vectordb.js +707 -0
- package/dist/vectordb/milvus-restful-vectordb.js.map +1 -0
- package/dist/vectordb/milvus-vectordb.d.ts +59 -0
- package/dist/vectordb/milvus-vectordb.d.ts.map +1 -0
- package/dist/vectordb/milvus-vectordb.js +641 -0
- package/dist/vectordb/milvus-vectordb.js.map +1 -0
- package/dist/vectordb/qdrant-vectordb.d.ts +124 -0
- package/dist/vectordb/qdrant-vectordb.d.ts.map +1 -0
- package/dist/vectordb/qdrant-vectordb.js +582 -0
- package/dist/vectordb/qdrant-vectordb.js.map +1 -0
- package/dist/vectordb/sparse/index.d.ts +4 -0
- package/dist/vectordb/sparse/index.d.ts.map +1 -0
- package/dist/vectordb/sparse/index.js +23 -0
- package/dist/vectordb/sparse/index.js.map +1 -0
- package/dist/vectordb/sparse/simple-bm25.d.ts +104 -0
- package/dist/vectordb/sparse/simple-bm25.d.ts.map +1 -0
- package/dist/vectordb/sparse/simple-bm25.js +189 -0
- package/dist/vectordb/sparse/simple-bm25.js.map +1 -0
- package/dist/vectordb/sparse/sparse-vector-generator.d.ts +54 -0
- package/dist/vectordb/sparse/sparse-vector-generator.d.ts.map +1 -0
- package/dist/vectordb/sparse/sparse-vector-generator.js +3 -0
- package/dist/vectordb/sparse/sparse-vector-generator.js.map +1 -0
- package/dist/vectordb/sparse/types.d.ts +38 -0
- package/dist/vectordb/sparse/types.d.ts.map +1 -0
- package/dist/vectordb/sparse/types.js +3 -0
- package/dist/vectordb/sparse/types.js.map +1 -0
- package/dist/vectordb/types.d.ts +120 -0
- package/dist/vectordb/types.d.ts.map +1 -0
- package/dist/vectordb/types.js +9 -0
- package/dist/vectordb/types.js.map +1 -0
- package/dist/vectordb/zilliz-utils.d.ts +135 -0
- package/dist/vectordb/zilliz-utils.d.ts.map +1 -0
- package/dist/vectordb/zilliz-utils.js +192 -0
- package/dist/vectordb/zilliz-utils.js.map +1 -0
- package/package.json +61 -0
@@ -0,0 +1,707 @@
|
|
1
|
+
"use strict";
|
2
|
+
/**
|
3
|
+
* Milvus RESTful Vector Database Implementation
|
4
|
+
*
|
5
|
+
* This RESTful implementation of Milvus vector database is specifically designed for
|
6
|
+
* environments with strict dependency constraints, e.g. VSCode Extensions, Chrome Extensions, etc.
|
7
|
+
*
|
8
|
+
* The standard Milvus gRPC implementation requires some dependencies and modules
|
9
|
+
* that are not available or restricted in these constrained environments. This RESTful
|
10
|
+
* implementation uses only HTTP requests, making it compatible with them.
|
11
|
+
*/
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
13
|
+
exports.MilvusRestfulVectorDatabase = void 0;
|
14
|
+
const types_1 = require("./types");
|
15
|
+
const zilliz_utils_1 = require("./zilliz-utils");
|
16
|
+
const base_vector_database_1 = require("./base/base-vector-database");
|
17
|
+
/**
|
18
|
+
* TODO: Change this usage to checkCollectionLimit()
|
19
|
+
* Wrapper function to handle collection creation with limit detection
|
20
|
+
* This is the single point where collection limit errors are detected and handled
|
21
|
+
*/
|
22
|
+
async function createCollectionWithLimitCheck(makeRequestFn, collectionSchema) {
|
23
|
+
try {
|
24
|
+
await makeRequestFn('/collections/create', 'POST', collectionSchema);
|
25
|
+
}
|
26
|
+
catch (error) {
|
27
|
+
// Check if the error message contains the collection limit exceeded pattern
|
28
|
+
const errorMessage = error.message || error.toString() || '';
|
29
|
+
if (/exceeded the limit number of collections/i.test(errorMessage)) {
|
30
|
+
// Throw the exact message string, not an Error object
|
31
|
+
throw types_1.COLLECTION_LIMIT_MESSAGE;
|
32
|
+
}
|
33
|
+
// Re-throw other errors as-is
|
34
|
+
throw error;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
/**
|
38
|
+
* Milvus Vector Database implementation using REST API
|
39
|
+
* This implementation is designed for environments where gRPC is not available,
|
40
|
+
* such as VSCode extensions or browser environments.
|
41
|
+
*/
|
42
|
+
class MilvusRestfulVectorDatabase extends base_vector_database_1.BaseVectorDatabase {
|
43
|
+
constructor(config) {
|
44
|
+
super(config);
|
45
|
+
this.baseUrl = null;
|
46
|
+
}
|
47
|
+
/**
|
48
|
+
* @override
|
49
|
+
* Implements the abstract initialize method from BaseVectorDatabase.
|
50
|
+
* Initializes the Milvus RESTful client by resolving the address and setting up the connection.
|
51
|
+
*/
|
52
|
+
async initialize() {
|
53
|
+
const resolvedAddress = await this.resolveAddress();
|
54
|
+
await this.initializeClient(resolvedAddress);
|
55
|
+
}
|
56
|
+
async initializeClient(address) {
|
57
|
+
// Ensure address has protocol prefix
|
58
|
+
let processedAddress = address;
|
59
|
+
if (!processedAddress.startsWith('http://') && !processedAddress.startsWith('https://')) {
|
60
|
+
processedAddress = `http://${processedAddress}`;
|
61
|
+
}
|
62
|
+
this.baseUrl = processedAddress.replace(/\/$/, '') + '/v2/vectordb';
|
63
|
+
console.log(`🔌 Connecting to Milvus REST API at: ${processedAddress}`);
|
64
|
+
}
|
65
|
+
/**
|
66
|
+
* Resolve address from config or token
|
67
|
+
* Common logic for both gRPC and REST implementations
|
68
|
+
*/
|
69
|
+
async resolveAddress() {
|
70
|
+
let finalConfig = { ...this.config };
|
71
|
+
// If address is not provided, get it using token
|
72
|
+
if (!finalConfig.address && finalConfig.token) {
|
73
|
+
finalConfig.address = await zilliz_utils_1.ClusterManager.getAddressFromToken(finalConfig.token);
|
74
|
+
}
|
75
|
+
if (!finalConfig.address) {
|
76
|
+
throw new Error('Address is required and could not be resolved from token');
|
77
|
+
}
|
78
|
+
return finalConfig.address;
|
79
|
+
}
|
80
|
+
/**
|
81
|
+
* Override to add baseUrl null check
|
82
|
+
*/
|
83
|
+
async ensureInitialized() {
|
84
|
+
await super.ensureInitialized();
|
85
|
+
if (!this.baseUrl) {
|
86
|
+
throw new Error('Base URL not initialized');
|
87
|
+
}
|
88
|
+
}
|
89
|
+
/**
|
90
|
+
* Ensure collection is loaded before search/query operations
|
91
|
+
*/
|
92
|
+
async ensureLoaded(collectionName) {
|
93
|
+
try {
|
94
|
+
const restfulConfig = this.config;
|
95
|
+
// Check if collection is loaded
|
96
|
+
const response = await this.makeRequest('/collections/get_load_state', 'POST', {
|
97
|
+
collectionName,
|
98
|
+
dbName: restfulConfig.database
|
99
|
+
});
|
100
|
+
const loadState = response.data?.loadState;
|
101
|
+
if (loadState !== 'LoadStateLoaded') {
|
102
|
+
console.log(`[MilvusRestfulDB] 🔄 Loading collection '${collectionName}' to memory...`);
|
103
|
+
await this.loadCollection(collectionName);
|
104
|
+
}
|
105
|
+
}
|
106
|
+
catch (error) {
|
107
|
+
console.error(`[MilvusRestfulDB] ❌ Failed to ensure collection '${collectionName}' is loaded:`, error);
|
108
|
+
throw error;
|
109
|
+
}
|
110
|
+
}
|
111
|
+
/**
|
112
|
+
* Make HTTP request to Milvus REST API
|
113
|
+
*/
|
114
|
+
async makeRequest(endpoint, method = 'POST', data) {
|
115
|
+
const url = `${this.baseUrl}${endpoint}`;
|
116
|
+
const headers = {
|
117
|
+
'Content-Type': 'application/json',
|
118
|
+
'Accept': 'application/json'
|
119
|
+
};
|
120
|
+
// Handle authentication
|
121
|
+
if (this.config.token) {
|
122
|
+
headers['Authorization'] = `Bearer ${this.config.token}`;
|
123
|
+
}
|
124
|
+
else if (this.config.username && this.config.password) {
|
125
|
+
headers['Authorization'] = `Bearer ${this.config.username}:${this.config.password}`;
|
126
|
+
}
|
127
|
+
const requestOptions = {
|
128
|
+
method,
|
129
|
+
headers,
|
130
|
+
};
|
131
|
+
if (data && method === 'POST') {
|
132
|
+
requestOptions.body = JSON.stringify(data);
|
133
|
+
}
|
134
|
+
try {
|
135
|
+
const response = await fetch(url, requestOptions);
|
136
|
+
if (!response.ok) {
|
137
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
138
|
+
}
|
139
|
+
const result = await response.json();
|
140
|
+
if (result.code !== 0 && result.code !== 200) {
|
141
|
+
throw new Error(`Milvus API error: ${result.message || 'Unknown error'}`);
|
142
|
+
}
|
143
|
+
return result;
|
144
|
+
}
|
145
|
+
catch (error) {
|
146
|
+
console.error(`[MilvusRestfulDB] Milvus REST API request failed:`, error);
|
147
|
+
throw error;
|
148
|
+
}
|
149
|
+
}
|
150
|
+
async createCollection(collectionName, dimension, description) {
|
151
|
+
await this.ensureInitialized();
|
152
|
+
try {
|
153
|
+
const restfulConfig = this.config;
|
154
|
+
// Build collection schema based on the original milvus-vectordb.ts implementation
|
155
|
+
// Note: REST API doesn't support description parameter in collection creation
|
156
|
+
// Unlike gRPC version, the description parameter is ignored in REST API
|
157
|
+
const collectionSchema = {
|
158
|
+
collectionName,
|
159
|
+
dbName: restfulConfig.database,
|
160
|
+
schema: {
|
161
|
+
enableDynamicField: false,
|
162
|
+
fields: [
|
163
|
+
{
|
164
|
+
fieldName: "id",
|
165
|
+
dataType: "VarChar",
|
166
|
+
isPrimary: true,
|
167
|
+
elementTypeParams: {
|
168
|
+
max_length: 512
|
169
|
+
}
|
170
|
+
},
|
171
|
+
{
|
172
|
+
fieldName: "vector",
|
173
|
+
dataType: "FloatVector",
|
174
|
+
elementTypeParams: {
|
175
|
+
dim: dimension
|
176
|
+
}
|
177
|
+
},
|
178
|
+
{
|
179
|
+
fieldName: "content",
|
180
|
+
dataType: "VarChar",
|
181
|
+
elementTypeParams: {
|
182
|
+
max_length: 65535
|
183
|
+
}
|
184
|
+
},
|
185
|
+
{
|
186
|
+
fieldName: "relativePath",
|
187
|
+
dataType: "VarChar",
|
188
|
+
elementTypeParams: {
|
189
|
+
max_length: 1024
|
190
|
+
}
|
191
|
+
},
|
192
|
+
{
|
193
|
+
fieldName: "startLine",
|
194
|
+
dataType: "Int64"
|
195
|
+
},
|
196
|
+
{
|
197
|
+
fieldName: "endLine",
|
198
|
+
dataType: "Int64"
|
199
|
+
},
|
200
|
+
{
|
201
|
+
fieldName: "fileExtension",
|
202
|
+
dataType: "VarChar",
|
203
|
+
elementTypeParams: {
|
204
|
+
max_length: 32
|
205
|
+
}
|
206
|
+
},
|
207
|
+
{
|
208
|
+
fieldName: "metadata",
|
209
|
+
dataType: "VarChar",
|
210
|
+
elementTypeParams: {
|
211
|
+
max_length: 65535
|
212
|
+
}
|
213
|
+
}
|
214
|
+
]
|
215
|
+
}
|
216
|
+
};
|
217
|
+
// Step 1: Create collection with schema
|
218
|
+
await createCollectionWithLimitCheck(this.makeRequest.bind(this), collectionSchema);
|
219
|
+
// Step 2: Create index for vector field (separate API call)
|
220
|
+
await this.createIndex(collectionName);
|
221
|
+
// Step 3: Load collection to memory for searching
|
222
|
+
await this.loadCollection(collectionName);
|
223
|
+
}
|
224
|
+
catch (error) {
|
225
|
+
console.error(`[MilvusRestfulDB] ❌ Failed to create collection '${collectionName}':`, error);
|
226
|
+
throw error;
|
227
|
+
}
|
228
|
+
}
|
229
|
+
/**
|
230
|
+
* Create index for vector field using the Index Create API
|
231
|
+
*/
|
232
|
+
async createIndex(collectionName) {
|
233
|
+
try {
|
234
|
+
const restfulConfig = this.config;
|
235
|
+
const indexParams = {
|
236
|
+
collectionName,
|
237
|
+
dbName: restfulConfig.database,
|
238
|
+
indexParams: [
|
239
|
+
{
|
240
|
+
fieldName: "vector",
|
241
|
+
indexName: "vector_index",
|
242
|
+
metricType: "COSINE",
|
243
|
+
index_type: "AUTOINDEX"
|
244
|
+
}
|
245
|
+
]
|
246
|
+
};
|
247
|
+
await this.makeRequest('/indexes/create', 'POST', indexParams);
|
248
|
+
}
|
249
|
+
catch (error) {
|
250
|
+
console.error(`[MilvusRestfulDB] ❌ Failed to create index for collection '${collectionName}':`, error);
|
251
|
+
throw error;
|
252
|
+
}
|
253
|
+
}
|
254
|
+
/**
|
255
|
+
* Load collection to memory for searching
|
256
|
+
*/
|
257
|
+
async loadCollection(collectionName) {
|
258
|
+
try {
|
259
|
+
const restfulConfig = this.config;
|
260
|
+
await this.makeRequest('/collections/load', 'POST', {
|
261
|
+
collectionName,
|
262
|
+
dbName: restfulConfig.database
|
263
|
+
});
|
264
|
+
}
|
265
|
+
catch (error) {
|
266
|
+
console.error(`[MilvusRestfulDB] ❌ Failed to load collection '${collectionName}':`, error);
|
267
|
+
throw error;
|
268
|
+
}
|
269
|
+
}
|
270
|
+
async dropCollection(collectionName) {
|
271
|
+
await this.ensureInitialized();
|
272
|
+
try {
|
273
|
+
const restfulConfig = this.config;
|
274
|
+
await this.makeRequest('/collections/drop', 'POST', {
|
275
|
+
collectionName,
|
276
|
+
dbName: restfulConfig.database
|
277
|
+
});
|
278
|
+
}
|
279
|
+
catch (error) {
|
280
|
+
console.error(`[MilvusRestfulDB] ❌ Failed to drop collection '${collectionName}':`, error);
|
281
|
+
throw error;
|
282
|
+
}
|
283
|
+
}
|
284
|
+
async hasCollection(collectionName) {
|
285
|
+
await this.ensureInitialized();
|
286
|
+
try {
|
287
|
+
const restfulConfig = this.config;
|
288
|
+
const response = await this.makeRequest('/collections/has', 'POST', {
|
289
|
+
collectionName,
|
290
|
+
dbName: restfulConfig.database
|
291
|
+
});
|
292
|
+
const exists = response.data?.has || false;
|
293
|
+
return exists;
|
294
|
+
}
|
295
|
+
catch (error) {
|
296
|
+
console.error(`[MilvusRestfulDB] ❌ Failed to check collection '${collectionName}' existence:`, error);
|
297
|
+
throw error;
|
298
|
+
}
|
299
|
+
}
|
300
|
+
async listCollections() {
|
301
|
+
await this.ensureInitialized();
|
302
|
+
try {
|
303
|
+
const restfulConfig = this.config;
|
304
|
+
const response = await this.makeRequest('/collections/list', 'POST', {
|
305
|
+
dbName: restfulConfig.database
|
306
|
+
});
|
307
|
+
return response.data || [];
|
308
|
+
}
|
309
|
+
catch (error) {
|
310
|
+
console.error(`[MilvusRestfulDB] ❌ Failed to list collections:`, error);
|
311
|
+
throw error;
|
312
|
+
}
|
313
|
+
}
|
314
|
+
async insert(collectionName, documents) {
|
315
|
+
await this.ensureInitialized();
|
316
|
+
await this.ensureLoaded(collectionName);
|
317
|
+
try {
|
318
|
+
const restfulConfig = this.config;
|
319
|
+
// Transform VectorDocument array to Milvus entity format
|
320
|
+
const data = documents.map(doc => ({
|
321
|
+
id: doc.id,
|
322
|
+
vector: doc.vector,
|
323
|
+
content: doc.content,
|
324
|
+
relativePath: doc.relativePath,
|
325
|
+
startLine: doc.startLine,
|
326
|
+
endLine: doc.endLine,
|
327
|
+
fileExtension: doc.fileExtension,
|
328
|
+
metadata: JSON.stringify(doc.metadata) // Convert metadata object to JSON string
|
329
|
+
}));
|
330
|
+
const insertRequest = {
|
331
|
+
collectionName,
|
332
|
+
data,
|
333
|
+
dbName: restfulConfig.database
|
334
|
+
};
|
335
|
+
await this.makeRequest('/entities/insert', 'POST', insertRequest);
|
336
|
+
}
|
337
|
+
catch (error) {
|
338
|
+
console.error(`[MilvusRestfulDB] ❌ Failed to insert documents into collection '${collectionName}':`, error);
|
339
|
+
throw error;
|
340
|
+
}
|
341
|
+
}
|
342
|
+
async search(collectionName, queryVector, options) {
|
343
|
+
await this.ensureInitialized();
|
344
|
+
await this.ensureLoaded(collectionName);
|
345
|
+
const topK = options?.topK || 10;
|
346
|
+
try {
|
347
|
+
const restfulConfig = this.config;
|
348
|
+
// Build search request according to Milvus REST API specification
|
349
|
+
const searchRequest = {
|
350
|
+
collectionName,
|
351
|
+
dbName: restfulConfig.database,
|
352
|
+
data: [queryVector], // Array of query vectors
|
353
|
+
annsField: "vector", // Vector field name
|
354
|
+
limit: topK,
|
355
|
+
outputFields: [
|
356
|
+
"content",
|
357
|
+
"relativePath",
|
358
|
+
"startLine",
|
359
|
+
"endLine",
|
360
|
+
"fileExtension",
|
361
|
+
"metadata"
|
362
|
+
],
|
363
|
+
searchParams: {
|
364
|
+
metricType: "COSINE", // Match the index metric type
|
365
|
+
params: {}
|
366
|
+
}
|
367
|
+
};
|
368
|
+
// Apply boolean expression filter if provided (e.g., fileExtension in ['.ts','.py'])
|
369
|
+
if (options?.filterExpr && options.filterExpr.trim().length > 0) {
|
370
|
+
searchRequest.filter = options.filterExpr;
|
371
|
+
}
|
372
|
+
const response = await this.makeRequest('/entities/search', 'POST', searchRequest);
|
373
|
+
// Transform response to VectorSearchResult format
|
374
|
+
const results = (response.data || []).map((item) => {
|
375
|
+
// Parse metadata from JSON string
|
376
|
+
let metadata = {};
|
377
|
+
try {
|
378
|
+
metadata = JSON.parse(item.metadata || '{}');
|
379
|
+
}
|
380
|
+
catch (error) {
|
381
|
+
console.warn(`[MilvusRestfulDB] Failed to parse metadata for item ${item.id}:`, error);
|
382
|
+
metadata = {};
|
383
|
+
}
|
384
|
+
return {
|
385
|
+
document: {
|
386
|
+
id: item.id?.toString() || '',
|
387
|
+
vector: queryVector, // Vector not returned in search results
|
388
|
+
content: item.content || '',
|
389
|
+
relativePath: item.relativePath || '',
|
390
|
+
startLine: item.startLine || 0,
|
391
|
+
endLine: item.endLine || 0,
|
392
|
+
fileExtension: item.fileExtension || '',
|
393
|
+
metadata: metadata
|
394
|
+
},
|
395
|
+
score: item.distance || 0
|
396
|
+
};
|
397
|
+
});
|
398
|
+
return results;
|
399
|
+
}
|
400
|
+
catch (error) {
|
401
|
+
console.error(`[MilvusRestfulDB] ❌ Failed to search in collection '${collectionName}':`, error);
|
402
|
+
throw error;
|
403
|
+
}
|
404
|
+
}
|
405
|
+
async delete(collectionName, ids) {
|
406
|
+
await this.ensureInitialized();
|
407
|
+
await this.ensureLoaded(collectionName);
|
408
|
+
try {
|
409
|
+
const restfulConfig = this.config;
|
410
|
+
// Build filter expression for deleting by IDs
|
411
|
+
// Format: id in ["id1", "id2", "id3"]
|
412
|
+
const filter = `id in [${ids.map(id => `"${id}"`).join(', ')}]`;
|
413
|
+
const deleteRequest = {
|
414
|
+
collectionName,
|
415
|
+
filter,
|
416
|
+
dbName: restfulConfig.database
|
417
|
+
};
|
418
|
+
await this.makeRequest('/entities/delete', 'POST', deleteRequest);
|
419
|
+
}
|
420
|
+
catch (error) {
|
421
|
+
console.error(`[MilvusRestfulDB] ❌ Failed to delete documents from collection '${collectionName}':`, error);
|
422
|
+
throw error;
|
423
|
+
}
|
424
|
+
}
|
425
|
+
async query(collectionName, filter, outputFields, limit) {
|
426
|
+
await this.ensureInitialized();
|
427
|
+
await this.ensureLoaded(collectionName);
|
428
|
+
try {
|
429
|
+
const restfulConfig = this.config;
|
430
|
+
const queryRequest = {
|
431
|
+
collectionName,
|
432
|
+
dbName: restfulConfig.database,
|
433
|
+
filter,
|
434
|
+
outputFields,
|
435
|
+
limit: limit || 16384, // Use provided limit or default
|
436
|
+
offset: 0
|
437
|
+
};
|
438
|
+
const response = await this.makeRequest('/entities/query', 'POST', queryRequest);
|
439
|
+
if (response.code !== 0) {
|
440
|
+
throw new Error(`Failed to query Milvus: ${response.message || 'Unknown error'}`);
|
441
|
+
}
|
442
|
+
return response.data || [];
|
443
|
+
}
|
444
|
+
catch (error) {
|
445
|
+
console.error(`[MilvusRestfulDB] ❌ Failed to query collection '${collectionName}':`, error);
|
446
|
+
throw error;
|
447
|
+
}
|
448
|
+
}
|
449
|
+
async createHybridCollection(collectionName, dimension, description) {
|
450
|
+
try {
|
451
|
+
const restfulConfig = this.config;
|
452
|
+
const collectionSchema = {
|
453
|
+
collectionName,
|
454
|
+
dbName: restfulConfig.database,
|
455
|
+
schema: {
|
456
|
+
enableDynamicField: false,
|
457
|
+
functions: [
|
458
|
+
{
|
459
|
+
name: "content_bm25_emb",
|
460
|
+
description: "content bm25 function",
|
461
|
+
type: "BM25",
|
462
|
+
inputFieldNames: ["content"],
|
463
|
+
outputFieldNames: ["sparse_vector"],
|
464
|
+
params: {},
|
465
|
+
},
|
466
|
+
],
|
467
|
+
fields: [
|
468
|
+
{
|
469
|
+
fieldName: "id",
|
470
|
+
dataType: "VarChar",
|
471
|
+
isPrimary: true,
|
472
|
+
elementTypeParams: {
|
473
|
+
max_length: 512
|
474
|
+
}
|
475
|
+
},
|
476
|
+
{
|
477
|
+
fieldName: "content",
|
478
|
+
dataType: "VarChar",
|
479
|
+
elementTypeParams: {
|
480
|
+
max_length: 65535,
|
481
|
+
enable_analyzer: true
|
482
|
+
}
|
483
|
+
},
|
484
|
+
{
|
485
|
+
fieldName: "vector",
|
486
|
+
dataType: "FloatVector",
|
487
|
+
elementTypeParams: {
|
488
|
+
dim: dimension
|
489
|
+
}
|
490
|
+
},
|
491
|
+
{
|
492
|
+
fieldName: "sparse_vector",
|
493
|
+
dataType: "SparseFloatVector"
|
494
|
+
},
|
495
|
+
{
|
496
|
+
fieldName: "relativePath",
|
497
|
+
dataType: "VarChar",
|
498
|
+
elementTypeParams: {
|
499
|
+
max_length: 1024
|
500
|
+
}
|
501
|
+
},
|
502
|
+
{
|
503
|
+
fieldName: "startLine",
|
504
|
+
dataType: "Int64"
|
505
|
+
},
|
506
|
+
{
|
507
|
+
fieldName: "endLine",
|
508
|
+
dataType: "Int64"
|
509
|
+
},
|
510
|
+
{
|
511
|
+
fieldName: "fileExtension",
|
512
|
+
dataType: "VarChar",
|
513
|
+
elementTypeParams: {
|
514
|
+
max_length: 32
|
515
|
+
}
|
516
|
+
},
|
517
|
+
{
|
518
|
+
fieldName: "metadata",
|
519
|
+
dataType: "VarChar",
|
520
|
+
elementTypeParams: {
|
521
|
+
max_length: 65535
|
522
|
+
}
|
523
|
+
}
|
524
|
+
]
|
525
|
+
}
|
526
|
+
};
|
527
|
+
// Step 1: Create collection with schema and functions
|
528
|
+
await createCollectionWithLimitCheck(this.makeRequest.bind(this), collectionSchema);
|
529
|
+
// Step 2: Create indexes for both vector fields
|
530
|
+
await this.createHybridIndexes(collectionName);
|
531
|
+
// Step 3: Load collection to memory for searching
|
532
|
+
await this.loadCollection(collectionName);
|
533
|
+
}
|
534
|
+
catch (error) {
|
535
|
+
console.error(`[MilvusRestfulDB] ❌ Failed to create hybrid collection '${collectionName}':`, error);
|
536
|
+
throw error;
|
537
|
+
}
|
538
|
+
}
|
539
|
+
async createHybridIndexes(collectionName) {
|
540
|
+
try {
|
541
|
+
const restfulConfig = this.config;
|
542
|
+
// Create index for dense vector
|
543
|
+
const denseIndexParams = {
|
544
|
+
collectionName,
|
545
|
+
dbName: restfulConfig.database,
|
546
|
+
indexParams: [
|
547
|
+
{
|
548
|
+
fieldName: "vector",
|
549
|
+
indexName: "vector_index",
|
550
|
+
metricType: "COSINE",
|
551
|
+
index_type: "AUTOINDEX"
|
552
|
+
}
|
553
|
+
]
|
554
|
+
};
|
555
|
+
await this.makeRequest('/indexes/create', 'POST', denseIndexParams);
|
556
|
+
// Create index for sparse vector
|
557
|
+
const sparseIndexParams = {
|
558
|
+
collectionName,
|
559
|
+
dbName: restfulConfig.database,
|
560
|
+
indexParams: [
|
561
|
+
{
|
562
|
+
fieldName: "sparse_vector",
|
563
|
+
indexName: "sparse_vector_index",
|
564
|
+
metricType: "BM25",
|
565
|
+
index_type: "SPARSE_INVERTED_INDEX"
|
566
|
+
}
|
567
|
+
]
|
568
|
+
};
|
569
|
+
await this.makeRequest('/indexes/create', 'POST', sparseIndexParams);
|
570
|
+
}
|
571
|
+
catch (error) {
|
572
|
+
console.error(`[MilvusRestfulDB] ❌ Failed to create hybrid indexes for collection '${collectionName}':`, error);
|
573
|
+
throw error;
|
574
|
+
}
|
575
|
+
}
|
576
|
+
async insertHybrid(collectionName, documents) {
|
577
|
+
await this.ensureInitialized();
|
578
|
+
await this.ensureLoaded(collectionName);
|
579
|
+
try {
|
580
|
+
const restfulConfig = this.config;
|
581
|
+
const data = documents.map(doc => ({
|
582
|
+
id: doc.id,
|
583
|
+
content: doc.content,
|
584
|
+
vector: doc.vector,
|
585
|
+
relativePath: doc.relativePath,
|
586
|
+
startLine: doc.startLine,
|
587
|
+
endLine: doc.endLine,
|
588
|
+
fileExtension: doc.fileExtension,
|
589
|
+
metadata: JSON.stringify(doc.metadata),
|
590
|
+
}));
|
591
|
+
const insertRequest = {
|
592
|
+
collectionName,
|
593
|
+
dbName: restfulConfig.database,
|
594
|
+
data: data
|
595
|
+
};
|
596
|
+
const response = await this.makeRequest('/entities/insert', 'POST', insertRequest);
|
597
|
+
if (response.code !== 0) {
|
598
|
+
throw new Error(`Insert failed: ${response.message || 'Unknown error'}`);
|
599
|
+
}
|
600
|
+
}
|
601
|
+
catch (error) {
|
602
|
+
console.error(`[MilvusRestfulDB] ❌ Failed to insert hybrid documents to collection '${collectionName}':`, error);
|
603
|
+
throw error;
|
604
|
+
}
|
605
|
+
}
|
606
|
+
async hybridSearch(collectionName, searchRequests, options) {
|
607
|
+
await this.ensureInitialized();
|
608
|
+
await this.ensureLoaded(collectionName);
|
609
|
+
try {
|
610
|
+
const restfulConfig = this.config;
|
611
|
+
console.log(`[MilvusRestfulDB] 🔍 Preparing hybrid search for collection: ${collectionName}`);
|
612
|
+
// Prepare search requests according to Milvus REST API hybrid search specification
|
613
|
+
// For dense vector search - data must be array of vectors: [[0.1, 0.2, 0.3, ...]]
|
614
|
+
const search_param_1 = {
|
615
|
+
data: Array.isArray(searchRequests[0].data) ? [searchRequests[0].data] : [[searchRequests[0].data]],
|
616
|
+
annsField: searchRequests[0].anns_field, // "vector"
|
617
|
+
limit: searchRequests[0].limit,
|
618
|
+
outputFields: ["*"],
|
619
|
+
searchParams: {
|
620
|
+
metricType: "COSINE",
|
621
|
+
params: searchRequests[0].param || { "nprobe": 10 }
|
622
|
+
}
|
623
|
+
};
|
624
|
+
// For sparse vector search - data must be array of queries: ["query text"]
|
625
|
+
const search_param_2 = {
|
626
|
+
data: Array.isArray(searchRequests[1].data) ? searchRequests[1].data : [searchRequests[1].data],
|
627
|
+
annsField: searchRequests[1].anns_field, // "sparse_vector"
|
628
|
+
limit: searchRequests[1].limit,
|
629
|
+
outputFields: ["*"],
|
630
|
+
searchParams: {
|
631
|
+
metricType: "BM25",
|
632
|
+
params: searchRequests[1].param || { "drop_ratio_search": 0.2 }
|
633
|
+
}
|
634
|
+
};
|
635
|
+
// Apply filter to both search parameters if provided
|
636
|
+
if (options?.filterExpr && options.filterExpr.trim().length > 0) {
|
637
|
+
search_param_1.filter = options.filterExpr;
|
638
|
+
search_param_2.filter = options.filterExpr;
|
639
|
+
}
|
640
|
+
const rerank_strategy = {
|
641
|
+
strategy: "rrf",
|
642
|
+
params: {
|
643
|
+
k: 100
|
644
|
+
}
|
645
|
+
};
|
646
|
+
console.log(`[MilvusRestfulDB] 🔍 Dense search params:`, JSON.stringify({
|
647
|
+
annsField: search_param_1.annsField,
|
648
|
+
limit: search_param_1.limit,
|
649
|
+
data_length: Array.isArray(search_param_1.data[0]) ? search_param_1.data[0].length : 'N/A',
|
650
|
+
searchParams: search_param_1.searchParams
|
651
|
+
}, null, 2));
|
652
|
+
console.log(`[MilvusRestfulDB] 🔍 Sparse search params:`, JSON.stringify({
|
653
|
+
annsField: search_param_2.annsField,
|
654
|
+
limit: search_param_2.limit,
|
655
|
+
query_text: typeof search_param_2.data[0] === 'string' ? search_param_2.data[0].substring(0, 50) + '...' : 'N/A',
|
656
|
+
searchParams: search_param_2.searchParams
|
657
|
+
}, null, 2));
|
658
|
+
const hybridSearchRequest = {
|
659
|
+
collectionName,
|
660
|
+
dbName: restfulConfig.database,
|
661
|
+
search: [search_param_1, search_param_2],
|
662
|
+
rerank: rerank_strategy,
|
663
|
+
limit: options?.limit || searchRequests[0]?.limit || 10,
|
664
|
+
outputFields: ['id', 'content', 'relativePath', 'startLine', 'endLine', 'fileExtension', 'metadata'],
|
665
|
+
};
|
666
|
+
console.log(`[MilvusRestfulDB] 🔍 Executing REST API hybrid search...`);
|
667
|
+
const response = await this.makeRequest('/entities/hybrid_search', 'POST', hybridSearchRequest);
|
668
|
+
if (response.code !== 0) {
|
669
|
+
throw new Error(`Hybrid search failed: ${response.message || 'Unknown error'}`);
|
670
|
+
}
|
671
|
+
const results = response.data || [];
|
672
|
+
console.log(`[MilvusRestfulDB] ✅ Found ${results.length} results from hybrid search`);
|
673
|
+
// Transform response to HybridSearchResult format
|
674
|
+
return results.map((result) => ({
|
675
|
+
document: {
|
676
|
+
id: result.id,
|
677
|
+
content: result.content,
|
678
|
+
vector: [], // Vector not returned in search results
|
679
|
+
sparse_vector: [], // Vector not returned in search results
|
680
|
+
relativePath: result.relativePath,
|
681
|
+
startLine: result.startLine,
|
682
|
+
endLine: result.endLine,
|
683
|
+
fileExtension: result.fileExtension,
|
684
|
+
metadata: JSON.parse(result.metadata || '{}'),
|
685
|
+
},
|
686
|
+
score: result.score || result.distance || 0,
|
687
|
+
}));
|
688
|
+
}
|
689
|
+
catch (error) {
|
690
|
+
console.error(`[MilvusRestfulDB] ❌ Failed to perform hybrid search on collection '${collectionName}':`, error);
|
691
|
+
throw error;
|
692
|
+
}
|
693
|
+
}
|
694
|
+
/**
|
695
|
+
* Check collection limit
|
696
|
+
* Returns true if collection can be created, false if limit exceeded
|
697
|
+
* TODO: Implement proper collection limit checking for REST API
|
698
|
+
*/
|
699
|
+
async checkCollectionLimit() {
|
700
|
+
// TODO: Implement REST API version of collection limit checking
|
701
|
+
// For now, always return true to maintain compatibility
|
702
|
+
console.warn('[MilvusRestfulDB] ⚠️ checkCollectionLimit not implemented for REST API - returning true');
|
703
|
+
return true;
|
704
|
+
}
|
705
|
+
}
|
706
|
+
exports.MilvusRestfulVectorDatabase = MilvusRestfulVectorDatabase;
|
707
|
+
//# sourceMappingURL=milvus-restful-vectordb.js.map
|