@smythos/sre 1.7.18 → 1.7.40
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/dist/index.js +120 -82
- package/dist/index.js.map +1 -1
- package/dist/types/Components/DataSourceIndexer.class.d.ts +4 -12
- package/dist/types/Components/GenAILLM.class.d.ts +5 -5
- package/dist/types/Components/RAG/DataSourceCleaner.class.d.ts +37 -0
- package/dist/types/Components/RAG/DataSourceComponent.class.d.ts +30 -0
- package/dist/types/Components/RAG/DataSourceIndexer.class.d.ts +14 -0
- package/dist/types/Components/RAG/DataSourceLookup.class.d.ts +36 -0
- package/dist/types/Components/index.d.ts +3 -3
- package/dist/types/helpers/Conversation.helper.d.ts +3 -0
- package/dist/types/index.d.ts +3 -3
- package/dist/types/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.d.ts +1 -0
- package/dist/types/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.d.ts +11 -4
- package/dist/types/subsystems/IO/VectorDB.service/embed/index.d.ts +5 -0
- package/dist/types/subsystems/LLMManager/LLM.inference.d.ts +10 -3
- package/dist/types/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.d.ts +4 -2
- package/dist/types/subsystems/LLMManager/ModelsProvider.service/connectors/JSONModelsProvider.class.d.ts +35 -0
- package/dist/types/subsystems/Security/Account.service/AccountConnector.d.ts +2 -2
- package/dist/types/subsystems/Security/ManagedVault.service/connectors/SecretManagerManagedVault.d.ts +10 -0
- package/dist/types/subsystems/Security/Vault.service/connectors/SecretsManager.class.d.ts +6 -2
- package/dist/types/types/LLM.types.d.ts +2 -0
- package/dist/types/types/VectorDB.types.d.ts +4 -0
- package/dist/types/utils/array.utils.d.ts +4 -0
- package/dist/types/utils/string.utils.d.ts +1 -0
- package/package.json +3 -3
- package/src/Components/APIEndpoint.class.ts +1 -6
- package/src/Components/Component.class.ts +14 -1
- package/src/Components/DataSourceIndexer.class.ts +148 -34
- package/src/Components/GenAILLM.class.ts +21 -11
- package/src/Components/RAG/DataSourceCleaner.class.ts +178 -0
- package/src/Components/RAG/DataSourceComponent.class.ts +111 -0
- package/src/Components/RAG/DataSourceIndexer.class.ts +254 -0
- package/src/Components/{DataSourceLookup.class.ts → RAG/DataSourceLookup.class.ts} +92 -3
- package/src/Components/ServerlessCode.class.ts +1 -4
- package/src/Components/index.ts +3 -3
- package/src/helpers/AWSLambdaCode.helper.ts +40 -45
- package/src/helpers/Conversation.helper.ts +14 -10
- package/src/helpers/S3Cache.helper.ts +2 -1
- package/src/index.ts +212 -212
- package/src/index.ts.bak +212 -212
- package/src/subsystems/IO/NKV.service/connectors/NKVRedis.class.ts +3 -1
- package/src/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.ts +145 -19
- package/src/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.ts +56 -22
- package/src/subsystems/IO/VectorDB.service/embed/GoogleEmbedding.ts +1 -0
- package/src/subsystems/IO/VectorDB.service/embed/OpenAIEmbedding.ts +2 -1
- package/src/subsystems/IO/VectorDB.service/embed/index.ts +18 -0
- package/src/subsystems/LLMManager/LLM.inference.ts +63 -47
- package/src/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.ts +35 -10
- package/src/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.ts +12 -4
- package/src/subsystems/LLMManager/LLM.service/connectors/Echo.class.ts +4 -4
- package/src/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.ts +105 -23
- package/src/subsystems/LLMManager/LLM.service/connectors/Groq.class.ts +17 -5
- package/src/subsystems/LLMManager/LLM.service/connectors/Ollama.class.ts +18 -3
- package/src/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.ts +14 -5
- package/src/subsystems/LLMManager/LLM.service/connectors/VertexAI.class.ts +6 -4
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.ts +5 -5
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.ts +8 -3
- package/src/subsystems/LLMManager/LLM.service/connectors/xAI.class.ts +9 -8
- package/src/subsystems/LLMManager/ModelsProvider.service/connectors/JSONModelsProvider.class.ts +126 -28
- package/src/subsystems/ObservabilityManager/Telemetry.service/connectors/OTel/OTel.class.ts +38 -6
- package/src/subsystems/Security/Account.service/AccountConnector.ts +3 -3
- package/src/subsystems/Security/ManagedVault.service/connectors/SecretManagerManagedVault.ts +111 -48
- package/src/subsystems/Security/Vault.service/connectors/SecretsManager.class.ts +41 -66
- package/src/types/LLM.types.ts +5 -0
- package/src/types/VectorDB.types.ts +4 -0
- package/src/utils/array.utils.ts +11 -0
- package/src/utils/base64.utils.ts +1 -1
- package/src/utils/string.utils.ts +3 -192
- package/src/Components/DataSourceCleaner.class.ts +0 -92
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
//==[ SRE: S3Storage ]======================
|
|
2
1
|
import { ConnectorService } from '@sre/Core/ConnectorsService';
|
|
3
2
|
import { JSONContentHelper } from '@sre/helpers/JsonContent.helper';
|
|
4
3
|
import { Logger } from '@sre/helpers/Log.helper';
|
|
@@ -17,12 +16,21 @@ import {
|
|
|
17
16
|
VectorDBResult,
|
|
18
17
|
VectorsResultData,
|
|
19
18
|
} from '@sre/types/VectorDB.types';
|
|
19
|
+
import { calcSizeMb } from '@sre/utils/string.utils';
|
|
20
20
|
import { CreateIndexSimpleReq, DataType, ErrorCode, FieldType, MilvusClient } from '@zilliz/milvus2-sdk-node';
|
|
21
21
|
import crypto from 'crypto';
|
|
22
22
|
import { jsonrepair } from 'jsonrepair';
|
|
23
23
|
import { EmbeddingsFactory } from '../embed';
|
|
24
24
|
import { BaseEmbedding, TEmbeddings } from '../embed/BaseEmbedding';
|
|
25
25
|
import { DeleteTarget, VectorDBConnector } from '../VectorDBConnector';
|
|
26
|
+
import { NKVConnector } from '@sre/IO/NKV.service/NKVConnector';
|
|
27
|
+
|
|
28
|
+
//! Due to current bug (still investigating), any consumer of this connector
|
|
29
|
+
//! needs to install @zilliz/milvus2-sdk-node in the package.json of the project so it can work
|
|
30
|
+
|
|
31
|
+
//* Note, we are storing Datasources info inside both NKV and Milvus (using some quirks).
|
|
32
|
+
//* The connector favors NKV as storage number 1, and Milvus acting as fallback storage.
|
|
33
|
+
//* This is because Milvus operations are heavy and can be slow the more u add big datasources
|
|
26
34
|
|
|
27
35
|
const console = Logger('Milvus');
|
|
28
36
|
|
|
@@ -42,7 +50,7 @@ export type MilvusConfig = {
|
|
|
42
50
|
};
|
|
43
51
|
|
|
44
52
|
// Define schema field names as a type for strong typing
|
|
45
|
-
type SchemaFieldNames = 'id' | 'text' | 'namespaceId' | 'datasourceId' | 'datasourceLabel' | 'vector' | 'acl' | 'user_metadata';
|
|
53
|
+
type SchemaFieldNames = 'id' | 'text' | 'namespaceId' | 'datasourceId' | 'datasourceLabel' | 'vector' | 'acl' | 'user_metadata' | 'smyth_metadata';
|
|
46
54
|
|
|
47
55
|
type SchemaField = FieldType & { name: SchemaFieldNames };
|
|
48
56
|
|
|
@@ -55,6 +63,7 @@ export class MilvusVectorDB extends VectorDBConnector {
|
|
|
55
63
|
public embedder: BaseEmbedding;
|
|
56
64
|
private SCHEMA_DEFINITION: SchemaField[];
|
|
57
65
|
private INDEX_PARAMS: IndexParams;
|
|
66
|
+
private nkvConnector: NKVConnector;
|
|
58
67
|
|
|
59
68
|
constructor(protected _settings: MilvusConfig) {
|
|
60
69
|
super(_settings);
|
|
@@ -72,16 +81,22 @@ export class MilvusVectorDB extends VectorDBConnector {
|
|
|
72
81
|
|
|
73
82
|
console.log('clientConfig', clientConfig);
|
|
74
83
|
|
|
75
|
-
this.client = new MilvusClient(clientConfig
|
|
84
|
+
this.client = new MilvusClient(clientConfig, undefined, undefined, undefined, {
|
|
85
|
+
'grpc.max_receive_message_length': 50 * 1024 * 1024,
|
|
86
|
+
'grpc.max_send_message_length': 50 * 1024 * 1024,
|
|
87
|
+
max_receive_message_length: 50 * 1024 * 1024,
|
|
88
|
+
max_send_message_length: 50 * 1024 * 1024,
|
|
89
|
+
});
|
|
76
90
|
console.info('Milvus client initialized');
|
|
77
91
|
this.accountConnector = ConnectorService.getAccountConnector();
|
|
78
92
|
this.cache = ConnectorService.getCacheConnector();
|
|
93
|
+
this.nkvConnector = ConnectorService.getNKVConnector();
|
|
79
94
|
|
|
80
95
|
if (!_settings.embeddings) {
|
|
81
96
|
_settings.embeddings = { provider: 'OpenAI', model: 'text-embedding-3-large', dimensions: 3072 };
|
|
82
97
|
}
|
|
83
98
|
|
|
84
|
-
if (!_settings.embeddings
|
|
99
|
+
if (!_settings.embeddings?.dimensions) _settings.embeddings.dimensions = 3072;
|
|
85
100
|
|
|
86
101
|
this.embedder = EmbeddingsFactory.create(_settings.embeddings.provider, _settings.embeddings);
|
|
87
102
|
|
|
@@ -128,6 +143,11 @@ export class MilvusVectorDB extends VectorDBConnector {
|
|
|
128
143
|
data_type: DataType.VarChar,
|
|
129
144
|
max_length: 2048,
|
|
130
145
|
},
|
|
146
|
+
{
|
|
147
|
+
name: 'smyth_metadata',
|
|
148
|
+
data_type: DataType.VarChar,
|
|
149
|
+
max_length: 65535,
|
|
150
|
+
},
|
|
131
151
|
];
|
|
132
152
|
this.INDEX_PARAMS = {
|
|
133
153
|
index_type: 'AUTOINDEX',
|
|
@@ -192,6 +212,11 @@ export class MilvusVectorDB extends VectorDBConnector {
|
|
|
192
212
|
throw new Error(`Error dropping collection: ${res}`);
|
|
193
213
|
}
|
|
194
214
|
|
|
215
|
+
// delete the linked datasources from nkv
|
|
216
|
+
await this.nkvConnector
|
|
217
|
+
.requester(acRequest.candidate as AccessCandidate)
|
|
218
|
+
.deleteAll(`vectorDB:${this.id}:namespaces:${preparedNs}:datasources`);
|
|
219
|
+
|
|
195
220
|
await this.deleteACL(AccessCandidate.clone(acRequest.candidate), namespace);
|
|
196
221
|
}
|
|
197
222
|
|
|
@@ -213,10 +238,13 @@ export class MilvusVectorDB extends VectorDBConnector {
|
|
|
213
238
|
const result = await this.client.search({
|
|
214
239
|
data: _vector as number[],
|
|
215
240
|
collection_name: preparedNs,
|
|
216
|
-
output_fields: ['id', 'text', this.USER_METADATA_KEY, 'namespaceId', 'datasourceId', 'datasourceLabel', 'vector'],
|
|
217
241
|
limit: options.topK || 10,
|
|
218
242
|
});
|
|
219
243
|
|
|
244
|
+
if (result.status.error_code !== ErrorCode.SUCCESS) {
|
|
245
|
+
throw new Error(`Error searching data: ${result.status.detail}`);
|
|
246
|
+
}
|
|
247
|
+
|
|
220
248
|
return result.results.map((match) => {
|
|
221
249
|
let _record = match;
|
|
222
250
|
if (match?.[this.USER_METADATA_KEY]) {
|
|
@@ -249,17 +277,45 @@ export class MilvusVectorDB extends VectorDBConnector {
|
|
|
249
277
|
|
|
250
278
|
const sourceType = this.embedder.detectSourceType(sourceWrapper[0].source);
|
|
251
279
|
if (sourceType === 'unknown' || sourceType === 'url') throw new Error('Unsupported source type');
|
|
280
|
+
|
|
252
281
|
const transformedSource = await this.embedder.transformSource(sourceWrapper, sourceType, acRequest.candidate as AccessCandidate);
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
282
|
+
|
|
283
|
+
const liveSchema = await this.client.describeCollection({
|
|
284
|
+
collection_name: preparedNs,
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// only incl the fields that are in the live schema
|
|
288
|
+
|
|
289
|
+
const preparedSource: Partial<Record<SchemaFieldNames, any>>[] = transformedSource.map((s) => {
|
|
290
|
+
function schemaFieldExists(field: SchemaFieldNames) {
|
|
291
|
+
return liveSchema.schema.fields.some((f) => f.name === field);
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
id: s.id,
|
|
295
|
+
text: s.metadata?.text,
|
|
296
|
+
user_metadata: s.metadata?.[this.USER_METADATA_KEY],
|
|
297
|
+
namespaceId: preparedNs,
|
|
298
|
+
datasourceId: s.metadata?.datasourceId, // legacy field
|
|
299
|
+
datasourceLabel: s.metadata?.datasourceLabel, // legacy field
|
|
300
|
+
vector: s.source,
|
|
301
|
+
acl: s.metadata?.acl,
|
|
302
|
+
...(schemaFieldExists('smyth_metadata')
|
|
303
|
+
? {
|
|
304
|
+
smyth_metadata: JSON.stringify({
|
|
305
|
+
datasource: {
|
|
306
|
+
id: s.metadata?.datasourceId,
|
|
307
|
+
label: s.metadata?.datasourceLabel,
|
|
308
|
+
chunkSize: s.metadata?.chunkSize,
|
|
309
|
+
chunkOverlap: s.metadata?.chunkOverlap,
|
|
310
|
+
createdAt: s.metadata?.createdAt,
|
|
311
|
+
datasourceSizeMb: s.metadata?.datasourceSizeMb,
|
|
312
|
+
chunkIndex: s.metadata?.chunkIndex,
|
|
313
|
+
},
|
|
314
|
+
}),
|
|
315
|
+
}
|
|
316
|
+
: {}),
|
|
317
|
+
};
|
|
318
|
+
});
|
|
263
319
|
|
|
264
320
|
const res = await this.client.insert({
|
|
265
321
|
collection_name: preparedNs,
|
|
@@ -322,6 +378,9 @@ export class MilvusVectorDB extends VectorDBConnector {
|
|
|
322
378
|
const acl = new ACL().addAccess(acRequest.candidate.role, acRequest.candidate.id, TAccessLevel.Owner);
|
|
323
379
|
const dsId = datasource.id || crypto.randomUUID();
|
|
324
380
|
|
|
381
|
+
if (!datasource.chunkSize) datasource.chunkSize = 1000;
|
|
382
|
+
if (!datasource.chunkOverlap) datasource.chunkOverlap = 200;
|
|
383
|
+
|
|
325
384
|
const formattedNs = this.constructNsName(acRequest.candidate as AccessCandidate, namespace);
|
|
326
385
|
const chunkedText = this.embedder.chunkText(datasource.text, {
|
|
327
386
|
chunkSize: datasource.chunkSize,
|
|
@@ -329,6 +388,7 @@ export class MilvusVectorDB extends VectorDBConnector {
|
|
|
329
388
|
});
|
|
330
389
|
const ids = Array.from({ length: chunkedText.length }, (_, i) => crypto.randomUUID());
|
|
331
390
|
const label = datasource.label || 'Untitled';
|
|
391
|
+
const totalSizeMb = calcSizeMb(datasource.text);
|
|
332
392
|
const source: IVectorDataSourceDto[] = chunkedText.map<IVectorDataSourceDto>((doc, i) => {
|
|
333
393
|
return {
|
|
334
394
|
id: ids[i],
|
|
@@ -338,6 +398,11 @@ export class MilvusVectorDB extends VectorDBConnector {
|
|
|
338
398
|
namespaceId: formattedNs,
|
|
339
399
|
datasourceId: dsId,
|
|
340
400
|
datasourceLabel: label,
|
|
401
|
+
chunkSize: datasource?.chunkSize?.toString(),
|
|
402
|
+
chunkOverlap: datasource?.chunkOverlap?.toString(),
|
|
403
|
+
createdAt: new Date().getTime().toString(),
|
|
404
|
+
datasourceSizeMb: totalSizeMb.toString(),
|
|
405
|
+
chunkIndex: i,
|
|
341
406
|
user_metadata: datasource.metadata ? jsonrepair(JSON.stringify(datasource.metadata)) : JSON.stringify({}),
|
|
342
407
|
},
|
|
343
408
|
};
|
|
@@ -354,7 +419,16 @@ export class MilvusVectorDB extends VectorDBConnector {
|
|
|
354
419
|
text: datasource.text,
|
|
355
420
|
vectorIds: _vIds.map((v) => v.id),
|
|
356
421
|
id: dsId,
|
|
422
|
+
chunkSize: datasource.chunkSize,
|
|
423
|
+
chunkOverlap: datasource.chunkOverlap,
|
|
424
|
+
createdAt: new Date(),
|
|
425
|
+
datasourceSizeMb: totalSizeMb,
|
|
357
426
|
};
|
|
427
|
+
|
|
428
|
+
await this.nkvConnector
|
|
429
|
+
.requester(acRequest.candidate as AccessCandidate)
|
|
430
|
+
.set(`vectorDB:${this.id}:namespaces:${formattedNs}:datasources`, dsId, JSON.stringify(dsData));
|
|
431
|
+
|
|
358
432
|
if (datasource.returnFullVectorInfo) {
|
|
359
433
|
dsData.vectorInfo = _vIds;
|
|
360
434
|
}
|
|
@@ -367,6 +441,10 @@ export class MilvusVectorDB extends VectorDBConnector {
|
|
|
367
441
|
const formattedNs = this.constructNsName(acRequest.candidate as AccessCandidate, namespace);
|
|
368
442
|
|
|
369
443
|
await this.delete(acRequest, namespace, { datasourceId });
|
|
444
|
+
|
|
445
|
+
await this.nkvConnector
|
|
446
|
+
.requester(acRequest.candidate as AccessCandidate)
|
|
447
|
+
.delete(`vectorDB:${this.id}:namespaces:${formattedNs}:datasources`, datasourceId);
|
|
370
448
|
}
|
|
371
449
|
|
|
372
450
|
@SecureConnector.AccessControl
|
|
@@ -374,12 +452,26 @@ export class MilvusVectorDB extends VectorDBConnector {
|
|
|
374
452
|
//const teamId = await this.accountConnector.getCandidateTeam(acRequest.candidate);
|
|
375
453
|
const formattedNs = this.constructNsName(acRequest.candidate as AccessCandidate, namespace);
|
|
376
454
|
|
|
455
|
+
//* [1] Get datasources from NKV
|
|
456
|
+
try {
|
|
457
|
+
const nkvDatasources = await this.nkvConnector
|
|
458
|
+
.requester(acRequest.candidate as AccessCandidate)
|
|
459
|
+
.list(`vectorDB:${this.id}:namespaces:${formattedNs}:datasources`)
|
|
460
|
+
.then((ds) => ds.map((d) => JSONContentHelper.create(d.data?.toString()).tryParse() as IStorageVectorDataSource));
|
|
461
|
+
|
|
462
|
+
return nkvDatasources;
|
|
463
|
+
} catch (error) {
|
|
464
|
+
console.error('[NKV] Error listing datasources: ', error);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
console.info('Trying to get datasources from Milvus');
|
|
468
|
+
//* [2] Get datasources from Milvus [EXPENSIVE OPERATION] that may exhaust rpc channel
|
|
377
469
|
// Use queryIterator for memory-efficient pagination
|
|
378
470
|
const batchSize = 1000; // Process 1000 records at a time
|
|
379
471
|
const iterator = await this.client.queryIterator({
|
|
380
472
|
collection_name: formattedNs,
|
|
381
473
|
batchSize: batchSize,
|
|
382
|
-
output_fields: ['id', 'text', this.USER_METADATA_KEY, 'namespaceId', 'datasourceId', 'datasourceLabel', 'vector'],
|
|
474
|
+
// output_fields: ['id', 'text', this.USER_METADATA_KEY, 'namespaceId', 'datasourceId', 'datasourceLabel', 'vector'],
|
|
383
475
|
});
|
|
384
476
|
|
|
385
477
|
// Group records by datasourceId using Map for efficient lookups
|
|
@@ -395,16 +487,19 @@ export class MilvusVectorDB extends VectorDBConnector {
|
|
|
395
487
|
namespaceId: formattedNs,
|
|
396
488
|
candidateId: acRequest.candidate.id,
|
|
397
489
|
candidateRole: acRequest.candidate.role,
|
|
398
|
-
text: record.text,
|
|
490
|
+
// text: record.text,
|
|
399
491
|
name: record.datasourceLabel,
|
|
400
492
|
metadata: record[this.USER_METADATA_KEY]
|
|
401
493
|
? JSONContentHelper.create(record[this.USER_METADATA_KEY].toString()).tryParse()
|
|
402
494
|
: undefined,
|
|
403
|
-
vectorIds: [],
|
|
404
495
|
id: datasourceId,
|
|
496
|
+
vectorIds: [], // to be filled iteratively
|
|
497
|
+
text: '', // to be filled iteratively
|
|
405
498
|
});
|
|
406
499
|
}
|
|
407
500
|
datasourceMap.get(datasourceId)!.vectorIds.push(record.id);
|
|
501
|
+
// the text here represents the total text of the datasource (not a vector-stored text)
|
|
502
|
+
datasourceMap.get(datasourceId)!.text += record.text;
|
|
408
503
|
}
|
|
409
504
|
}
|
|
410
505
|
} finally {
|
|
@@ -418,10 +513,41 @@ export class MilvusVectorDB extends VectorDBConnector {
|
|
|
418
513
|
protected async getDatasource(acRequest: AccessRequest, namespace: string, datasourceId: string): Promise<IStorageVectorDataSource | undefined> {
|
|
419
514
|
//const teamId = await this.accountConnector.getCandidateTeam(acRequest.candidate);
|
|
420
515
|
const formattedNs = this.constructNsName(acRequest.candidate as AccessCandidate, namespace);
|
|
516
|
+
|
|
517
|
+
//* [1] Get datasource from NKV
|
|
518
|
+
try {
|
|
519
|
+
const nkvDatasource = await this.nkvConnector
|
|
520
|
+
.requester(acRequest.candidate as AccessCandidate)
|
|
521
|
+
.get(`vectorDB:${this.id}:namespaces:${formattedNs}:datasources`, datasourceId)
|
|
522
|
+
.then((ds) => JSONContentHelper.create(ds?.toString()).tryParse() as IStorageVectorDataSource);
|
|
523
|
+
|
|
524
|
+
if (nkvDatasource) {
|
|
525
|
+
return nkvDatasource;
|
|
526
|
+
} else {
|
|
527
|
+
console.info('Datasource not found in NKV');
|
|
528
|
+
}
|
|
529
|
+
} catch (error) {
|
|
530
|
+
console.error('[NKV] Error getting datasource: ', error);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
console.info('Trying to get datasource from Milvus');
|
|
534
|
+
|
|
535
|
+
//* [2] Get datasource from Milvus
|
|
421
536
|
const res = await this.client.query({
|
|
422
537
|
collection_name: formattedNs,
|
|
423
538
|
expr: `datasourceId == "${datasourceId}"`,
|
|
424
|
-
output_fields: [
|
|
539
|
+
// output_fields: [
|
|
540
|
+
// 'id',
|
|
541
|
+
// 'text',
|
|
542
|
+
// this.USER_METADATA_KEY,
|
|
543
|
+
// 'namespaceId',
|
|
544
|
+
// 'datasourceId',
|
|
545
|
+
// 'datasourceLabel',
|
|
546
|
+
// 'vector',
|
|
547
|
+
// 'chunkSize',
|
|
548
|
+
// 'chunkOverlap',
|
|
549
|
+
// 'createdAt',
|
|
550
|
+
// ],
|
|
425
551
|
});
|
|
426
552
|
// if 0 results, throw error
|
|
427
553
|
if (res.data.length === 0) {
|
|
@@ -24,20 +24,29 @@ import { CacheConnector } from '@sre/MemoryManager/Cache.service/CacheConnector'
|
|
|
24
24
|
import crypto from 'crypto';
|
|
25
25
|
import { BaseEmbedding, TEmbeddings } from '../embed/BaseEmbedding';
|
|
26
26
|
import { EmbeddingsFactory, SupportedProviders, SupportedModels } from '../embed';
|
|
27
|
-
|
|
27
|
+
import { calcSizeMb } from '@sre/utils/string.utils';
|
|
28
28
|
import { jsonrepair } from 'jsonrepair';
|
|
29
|
+
import { chunkArr } from '@sre/utils/array.utils';
|
|
29
30
|
|
|
30
31
|
const console = Logger('Pinecone VectorDB');
|
|
31
32
|
|
|
32
33
|
export type PineconeConfig = {
|
|
33
34
|
/**
|
|
34
|
-
* The Pinecone API key
|
|
35
|
+
* The Pinecone API key [LEGACY]
|
|
35
36
|
*/
|
|
36
|
-
apiKey
|
|
37
|
+
apiKey?: string;
|
|
37
38
|
/**
|
|
38
|
-
* The Pinecone index name
|
|
39
|
+
* The Pinecone index name [LEGACY]
|
|
39
40
|
*/
|
|
40
|
-
indexName
|
|
41
|
+
indexName?: string;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The Pinecone credentials [New unified format]
|
|
45
|
+
*/
|
|
46
|
+
credentials?: {
|
|
47
|
+
apiKey: string;
|
|
48
|
+
indexName: string;
|
|
49
|
+
};
|
|
41
50
|
/**
|
|
42
51
|
* The embeddings model to use
|
|
43
52
|
*/
|
|
@@ -55,28 +64,28 @@ export class PineconeVectorDB extends VectorDBConnector {
|
|
|
55
64
|
|
|
56
65
|
constructor(protected _settings: PineconeConfig) {
|
|
57
66
|
super(_settings);
|
|
58
|
-
if (!_settings.apiKey) {
|
|
67
|
+
if (!_settings.apiKey && !_settings?.credentials?.apiKey) {
|
|
59
68
|
console.warn('Missing Pinecone API key : returning empty Pinecone connector');
|
|
60
69
|
return;
|
|
61
70
|
}
|
|
62
|
-
if (!_settings.indexName) {
|
|
71
|
+
if (!_settings.indexName && !_settings?.credentials?.indexName) {
|
|
63
72
|
console.warn('Missing Pinecone index name : returning empty Pinecone connector');
|
|
64
73
|
return;
|
|
65
74
|
}
|
|
66
75
|
|
|
67
76
|
this.client = new Pinecone({
|
|
68
|
-
apiKey: _settings.apiKey,
|
|
77
|
+
apiKey: _settings.apiKey || _settings.credentials?.apiKey,
|
|
69
78
|
});
|
|
70
79
|
console.info('Pinecone client initialized');
|
|
71
|
-
console.info('Pinecone index name:', _settings.indexName);
|
|
72
|
-
this.indexName = _settings.indexName;
|
|
80
|
+
console.info('Pinecone index name:', _settings.indexName || _settings.credentials?.indexName);
|
|
81
|
+
this.indexName = _settings.indexName || _settings.credentials?.indexName;
|
|
73
82
|
this.accountConnector = ConnectorService.getAccountConnector();
|
|
74
83
|
this.cache = ConnectorService.getCacheConnector();
|
|
75
84
|
this.nkvConnector = ConnectorService.getNKVConnector();
|
|
76
85
|
if (!_settings.embeddings) {
|
|
77
86
|
_settings.embeddings = { provider: 'OpenAI', model: 'text-embedding-3-large', dimensions: 3072 };
|
|
78
87
|
}
|
|
79
|
-
if (!_settings.embeddings
|
|
88
|
+
if (!_settings.embeddings?.dimensions) _settings.embeddings.dimensions = 3072;
|
|
80
89
|
|
|
81
90
|
this.embedder = EmbeddingsFactory.create(_settings.embeddings.provider, _settings.embeddings);
|
|
82
91
|
}
|
|
@@ -229,17 +238,28 @@ export class PineconeVectorDB extends VectorDBConnector {
|
|
|
229
238
|
const sourceType = this.embedder.detectSourceType(sourceWrapper[0].source);
|
|
230
239
|
if (sourceType === 'unknown' || sourceType === 'url') throw new Error('Invalid source type');
|
|
231
240
|
const transformedSource = await this.embedder.transformSource(sourceWrapper, sourceType, acRequest.candidate as AccessCandidate);
|
|
232
|
-
const
|
|
241
|
+
const preparedSources = transformedSource.map((s) => ({
|
|
233
242
|
id: s.id,
|
|
234
243
|
values: s.source as number[],
|
|
235
244
|
metadata: s.metadata,
|
|
236
245
|
}));
|
|
237
246
|
|
|
238
|
-
//
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
247
|
+
// pinecone advices to use batches of 100 at a time
|
|
248
|
+
const batchSize = 100;
|
|
249
|
+
const chunkedVectors = chunkArr(preparedSources, batchSize);
|
|
250
|
+
|
|
251
|
+
// await this.client
|
|
252
|
+
// .Index(this.indexName)
|
|
253
|
+
// .namespace(this.constructNsName(acRequest.candidate as AccessCandidate, namespace))
|
|
254
|
+
// .upsert(preparedSources);
|
|
255
|
+
|
|
256
|
+
const promises = chunkedVectors.map(async (chunk) => {
|
|
257
|
+
await this.client
|
|
258
|
+
.Index(this.indexName)
|
|
259
|
+
.namespace(this.constructNsName(acRequest.candidate as AccessCandidate, namespace))
|
|
260
|
+
.upsert(chunk);
|
|
261
|
+
});
|
|
262
|
+
await Promise.all(promises);
|
|
243
263
|
|
|
244
264
|
const accessCandidate = acRequest.candidate;
|
|
245
265
|
|
|
@@ -249,7 +269,7 @@ export class PineconeVectorDB extends VectorDBConnector {
|
|
|
249
269
|
await this.setACL(acRequest, namespace, acl);
|
|
250
270
|
}
|
|
251
271
|
|
|
252
|
-
return
|
|
272
|
+
return preparedSources.map((s) => {
|
|
253
273
|
const { text, acl, user_metadata, ...restMetadata } = s.metadata || {};
|
|
254
274
|
return {
|
|
255
275
|
id: s.id,
|
|
@@ -272,10 +292,16 @@ export class PineconeVectorDB extends VectorDBConnector {
|
|
|
272
292
|
} else {
|
|
273
293
|
const _ids = Array.isArray(deleteTarget) ? deleteTarget : [deleteTarget];
|
|
274
294
|
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
295
|
+
const batchSize = 800;
|
|
296
|
+
const chunkedIds = chunkArr(_ids, batchSize);
|
|
297
|
+
|
|
298
|
+
const promises = chunkedIds.map(async (chunk) => {
|
|
299
|
+
await this.client
|
|
300
|
+
.Index(this.indexName)
|
|
301
|
+
.namespace(this.constructNsName(acRequest.candidate as AccessCandidate, namespace))
|
|
302
|
+
.deleteMany(chunk);
|
|
303
|
+
});
|
|
304
|
+
await Promise.all(promises);
|
|
279
305
|
}
|
|
280
306
|
}
|
|
281
307
|
|
|
@@ -285,6 +311,9 @@ export class PineconeVectorDB extends VectorDBConnector {
|
|
|
285
311
|
const acl = new ACL().addAccess(acRequest.candidate.role, acRequest.candidate.id, TAccessLevel.Owner);
|
|
286
312
|
const dsId = datasource.id || crypto.randomUUID();
|
|
287
313
|
|
|
314
|
+
if (!datasource.chunkSize) datasource.chunkSize = 2000;
|
|
315
|
+
if (!datasource.chunkOverlap) datasource.chunkOverlap = 200;
|
|
316
|
+
|
|
288
317
|
const formattedNs = this.constructNsName(acRequest.candidate as AccessCandidate, namespace);
|
|
289
318
|
const chunkedText = this.embedder.chunkText(datasource.text, {
|
|
290
319
|
chunkSize: datasource.chunkSize,
|
|
@@ -301,6 +330,7 @@ export class PineconeVectorDB extends VectorDBConnector {
|
|
|
301
330
|
namespaceId: formattedNs,
|
|
302
331
|
datasourceId: dsId,
|
|
303
332
|
datasourceLabel: label,
|
|
333
|
+
chunkIndex: i,
|
|
304
334
|
user_metadata: datasource.metadata ? jsonrepair(JSON.stringify(datasource.metadata)) : undefined,
|
|
305
335
|
},
|
|
306
336
|
};
|
|
@@ -317,6 +347,10 @@ export class PineconeVectorDB extends VectorDBConnector {
|
|
|
317
347
|
text: datasource.text,
|
|
318
348
|
vectorIds: _vIds.map((v) => v.id),
|
|
319
349
|
id: dsId,
|
|
350
|
+
datasourceSizeMb: calcSizeMb(datasource.text),
|
|
351
|
+
chunkSize: datasource.chunkSize,
|
|
352
|
+
chunkOverlap: datasource.chunkOverlap,
|
|
353
|
+
createdAt: new Date(),
|
|
320
354
|
};
|
|
321
355
|
if (datasource.returnFullVectorInfo) {
|
|
322
356
|
dsData.vectorInfo = _vIds;
|
|
@@ -18,6 +18,7 @@ export class GoogleEmbeds extends BaseEmbedding {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
async embedTexts(texts: string[], candidate: AccessCandidate): Promise<number[][]> {
|
|
21
|
+
// we split into batches to avoid provider limits
|
|
21
22
|
const batches = this.chunkArr(this.processTexts(texts), this.batchSize);
|
|
22
23
|
|
|
23
24
|
const batchRequests = batches.map((batch) => {
|
|
@@ -24,7 +24,7 @@ export class OpenAIEmbeds extends BaseEmbedding {
|
|
|
24
24
|
protected client: OpenAIClient;
|
|
25
25
|
protected clientConfig: ClientOptions;
|
|
26
26
|
|
|
27
|
-
public static models = ['text-embedding-
|
|
27
|
+
public static models = ['text-embedding-3-large', 'text-embedding-ada-002'];
|
|
28
28
|
public canSpecifyDimensions = true;
|
|
29
29
|
|
|
30
30
|
constructor(private settings?: Partial<TEmbeddings>) {
|
|
@@ -41,6 +41,7 @@ export class OpenAIEmbeds extends BaseEmbedding {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
async embedTexts(texts: string[], candidate: AccessCandidate): Promise<number[][]> {
|
|
44
|
+
// we split into batches to avoid provider limits
|
|
44
45
|
const batches = this.chunkArr(this.processTexts(texts), this.batchSize);
|
|
45
46
|
|
|
46
47
|
const batchRequests = batches.map((batch) => {
|
|
@@ -34,4 +34,22 @@ export class EmbeddingsFactory {
|
|
|
34
34
|
|
|
35
35
|
return new supportedProviders[provider as SupportedProviders].embedder(config);
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
public static getProviderByModel(model: SupportedModels): SupportedProviders {
|
|
39
|
+
return Object.keys(supportedProviders).find((provider) => supportedProviders[provider].models.includes(model)) as SupportedProviders;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public static getModels() {
|
|
43
|
+
return Object.keys(supportedProviders)
|
|
44
|
+
.reduce((acc, provider) => {
|
|
45
|
+
acc.push(
|
|
46
|
+
...supportedProviders[provider].models.map((model) => ({
|
|
47
|
+
provider,
|
|
48
|
+
model,
|
|
49
|
+
}))
|
|
50
|
+
);
|
|
51
|
+
return acc;
|
|
52
|
+
}, [] as { provider: SupportedProviders; model: SupportedModels[SupportedProviders] }[])
|
|
53
|
+
.filter((item) => item.model !== 'text-embedding-ada-002'); //! SPECIAL case for ada-002, it doesn't support dimensions passing
|
|
54
|
+
}
|
|
37
55
|
}
|