@smythos/sre 1.7.1 → 1.7.5

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 (48) hide show
  1. package/dist/index.js +33 -31
  2. package/dist/index.js.map +1 -1
  3. package/dist/types/helpers/BinaryInput.helper.d.ts +1 -1
  4. package/dist/types/helpers/LocalCache.helper.d.ts +18 -0
  5. package/dist/types/helpers/TemplateString.helper.d.ts +2 -1
  6. package/dist/types/subsystems/IO/VectorDB.service/VectorDBConnector.d.ts +4 -4
  7. package/dist/types/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.d.ts +2 -2
  8. package/dist/types/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.d.ts +2 -2
  9. package/dist/types/subsystems/IO/VectorDB.service/connectors/RAMVecrtorDB.class.d.ts +2 -2
  10. package/dist/types/subsystems/IO/VectorDB.service/embed/BaseEmbedding.d.ts +16 -9
  11. package/dist/types/subsystems/IO/VectorDB.service/embed/index.d.ts +4 -1
  12. package/dist/types/subsystems/LLMManager/LLM.inference.d.ts +36 -2
  13. package/dist/types/types/LLM.types.d.ts +54 -31
  14. package/dist/types/types/VectorDB.types.d.ts +6 -3
  15. package/dist/types/utils/string.utils.d.ts +0 -4
  16. package/package.json +1 -1
  17. package/src/Components/Classifier.class.ts +8 -2
  18. package/src/Components/GenAILLM.class.ts +11 -7
  19. package/src/Components/LLMAssistant.class.ts +12 -3
  20. package/src/Components/ScrapflyWebScrape.class.ts +8 -1
  21. package/src/Components/TavilyWebSearch.class.ts +4 -1
  22. package/src/Core/SmythRuntime.class.ts +13 -2
  23. package/src/helpers/BinaryInput.helper.ts +8 -8
  24. package/src/helpers/Conversation.helper.ts +11 -1
  25. package/src/helpers/LocalCache.helper.ts +18 -0
  26. package/src/helpers/TemplateString.helper.ts +20 -9
  27. package/src/index.ts +208 -208
  28. package/src/index.ts.bak +208 -208
  29. package/src/subsystems/AgentManager/Agent.class.ts +2 -0
  30. package/src/subsystems/AgentManager/AgentData.service/AgentDataConnector.ts +6 -5
  31. package/src/subsystems/AgentManager/AgentLogger.class.ts +1 -1
  32. package/src/subsystems/IO/VectorDB.service/VectorDBConnector.ts +15 -4
  33. package/src/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.ts +31 -10
  34. package/src/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.ts +27 -10
  35. package/src/subsystems/IO/VectorDB.service/connectors/RAMVecrtorDB.class.ts +25 -9
  36. package/src/subsystems/IO/VectorDB.service/embed/BaseEmbedding.ts +182 -12
  37. package/src/subsystems/IO/VectorDB.service/embed/GoogleEmbedding.ts +1 -1
  38. package/src/subsystems/IO/VectorDB.service/embed/OpenAIEmbedding.ts +1 -1
  39. package/src/subsystems/IO/VectorDB.service/embed/index.ts +12 -2
  40. package/src/subsystems/LLMManager/LLM.inference.ts +76 -17
  41. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.ts +3 -2
  42. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.ts +2 -2
  43. package/src/subsystems/LLMManager/ModelsProvider.service/ModelsProviderConnector.ts +2 -2
  44. package/src/subsystems/LLMManager/ModelsProvider.service/connectors/JSONModelsProvider.class.ts +4 -1
  45. package/src/subsystems/MemoryManager/Cache.service/connectors/RedisCache.class.ts +12 -0
  46. package/src/types/LLM.types.ts +66 -38
  47. package/src/types/VectorDB.types.ts +7 -3
  48. package/src/utils/string.utils.ts +193 -191
@@ -9,8 +9,14 @@ import { ACL } from '@sre/Security/AccessControl/ACL.class';
9
9
  import { AccountConnector } from '@sre/Security/Account.service/AccountConnector';
10
10
  import { SecureConnector } from '@sre/Security/SecureConnector.class';
11
11
  import { IAccessCandidate, IACL, TAccessLevel } from '@sre/types/ACL.types';
12
- import { DatasourceDto, IStorageVectorDataSource, IVectorDataSourceDto, QueryOptions, VectorsResultData } from '@sre/types/VectorDB.types';
13
- import { chunkText } from '@sre/utils/string.utils';
12
+ import {
13
+ DatasourceDto,
14
+ IStorageVectorDataSource,
15
+ IVectorDataSourceDto,
16
+ QueryOptions,
17
+ VectorDBResult,
18
+ VectorsResultData,
19
+ } from '@sre/types/VectorDB.types';
14
20
  import { CreateIndexSimpleReq, DataType, ErrorCode, FieldType, MilvusClient } from '@zilliz/milvus2-sdk-node';
15
21
  import crypto from 'crypto';
16
22
  import { jsonrepair } from 'jsonrepair';
@@ -72,10 +78,10 @@ export class MilvusVectorDB extends VectorDBConnector {
72
78
  this.cache = ConnectorService.getCacheConnector();
73
79
 
74
80
  if (!_settings.embeddings) {
75
- _settings.embeddings = { provider: 'OpenAI', model: 'text-embedding-3-large', params: { dimensions: 1024 } };
81
+ _settings.embeddings = { provider: 'OpenAI', model: 'text-embedding-3-large', dimensions: 1024 };
76
82
  }
77
- if (!_settings.embeddings.params) _settings.embeddings.params = { dimensions: 1024 };
78
- if (!_settings.embeddings.params?.dimensions) _settings.embeddings.params.dimensions = 1024;
83
+
84
+ if (!_settings.embeddings.dimensions) _settings.embeddings.dimensions = 1024;
79
85
 
80
86
  this.embedder = EmbeddingsFactory.create(_settings.embeddings.provider, _settings.embeddings);
81
87
 
@@ -231,7 +237,7 @@ export class MilvusVectorDB extends VectorDBConnector {
231
237
  acRequest: AccessRequest,
232
238
  namespace: string,
233
239
  sourceWrapper: IVectorDataSourceDto | IVectorDataSourceDto[]
234
- ): Promise<string[]> {
240
+ ): Promise<VectorDBResult[]> {
235
241
  //const teamId = await this.accountConnector.getCandidateTeam(acRequest.candidate);
236
242
  sourceWrapper = Array.isArray(sourceWrapper) ? sourceWrapper : [sourceWrapper];
237
243
  const preparedNs = this.constructNsName(acRequest.candidate as AccessCandidate, namespace);
@@ -264,7 +270,18 @@ export class MilvusVectorDB extends VectorDBConnector {
264
270
  throw new Error(`Error inserting data: ${res?.status?.error_code}`);
265
271
  }
266
272
 
267
- return preparedSource.map((s) => s.id);
273
+ return preparedSource.map((s) => {
274
+ const { text, acl, user_metadata, ...restMetadata } = s || {};
275
+ return {
276
+ id: s.id,
277
+ values: s.vector as number[],
278
+ text: text as string,
279
+ metadata: {
280
+ ...restMetadata,
281
+ ...((typeof user_metadata === 'string' ? JSON.parse(user_metadata) : user_metadata) as Record<string, any>),
282
+ },
283
+ };
284
+ });
268
285
  }
269
286
 
270
287
  @SecureConnector.AccessControl
@@ -306,7 +323,7 @@ export class MilvusVectorDB extends VectorDBConnector {
306
323
  const dsId = datasource.id || crypto.randomUUID();
307
324
 
308
325
  const formattedNs = this.constructNsName(acRequest.candidate as AccessCandidate, namespace);
309
- const chunkedText = chunkText(datasource.text, {
326
+ const chunkedText = this.embedder.chunkText(datasource.text, {
310
327
  chunkSize: datasource.chunkSize,
311
328
  chunkOverlap: datasource.chunkOverlap,
312
329
  });
@@ -328,16 +345,20 @@ export class MilvusVectorDB extends VectorDBConnector {
328
345
 
329
346
  const _vIds = await this.insert(acRequest, namespace, source);
330
347
 
331
- return {
348
+ const dsData: IStorageVectorDataSource = {
332
349
  namespaceId: formattedNs,
333
350
  candidateId: acRequest.candidate.id,
334
351
  candidateRole: acRequest.candidate.role,
335
352
  name: label,
336
353
  metadata: datasource.metadata ? jsonrepair(JSON.stringify(datasource.metadata)) : undefined,
337
354
  text: datasource.text,
338
- vectorIds: _vIds,
355
+ vectorIds: _vIds.map((v) => v.id),
339
356
  id: dsId,
340
357
  };
358
+ if (datasource.returnFullVectorInfo) {
359
+ dsData.vectorInfo = _vIds;
360
+ }
361
+ return dsData;
341
362
  }
342
363
 
343
364
  @SecureConnector.AccessControl
@@ -11,6 +11,7 @@ import {
11
11
  IStorageVectorNamespace,
12
12
  IVectorDataSourceDto,
13
13
  QueryOptions,
14
+ VectorDBResult,
14
15
  VectorsResultData,
15
16
  } from '@sre/types/VectorDB.types';
16
17
  import { Pinecone } from '@pinecone-database/pinecone';
@@ -23,7 +24,7 @@ import { CacheConnector } from '@sre/MemoryManager/Cache.service/CacheConnector'
23
24
  import crypto from 'crypto';
24
25
  import { BaseEmbedding, TEmbeddings } from '../embed/BaseEmbedding';
25
26
  import { EmbeddingsFactory, SupportedProviders, SupportedModels } from '../embed';
26
- import { chunkText } from '@sre/utils/string.utils';
27
+
27
28
  import { jsonrepair } from 'jsonrepair';
28
29
 
29
30
  const console = Logger('Pinecone VectorDB');
@@ -73,10 +74,9 @@ export class PineconeVectorDB extends VectorDBConnector {
73
74
  this.cache = ConnectorService.getCacheConnector();
74
75
  this.nkvConnector = ConnectorService.getNKVConnector();
75
76
  if (!_settings.embeddings) {
76
- _settings.embeddings = { provider: 'OpenAI', model: 'text-embedding-3-large', params: { dimensions: 1024 } };
77
+ _settings.embeddings = { provider: 'OpenAI', model: 'text-embedding-3-large', dimensions: 1024 };
77
78
  }
78
- if (!_settings.embeddings.params) _settings.embeddings.params = { dimensions: 1024 };
79
- if (!_settings.embeddings.params?.dimensions) _settings.embeddings.params.dimensions = 1024;
79
+ if (!_settings.embeddings.dimensions) _settings.embeddings.dimensions = 1024;
80
80
 
81
81
  this.embedder = EmbeddingsFactory.create(_settings.embeddings.provider, _settings.embeddings);
82
82
  }
@@ -189,11 +189,14 @@ export class PineconeVectorDB extends VectorDBConnector {
189
189
  match.metadata[this.USER_METADATA_KEY] = JSONContentHelper.create(match.metadata[this.USER_METADATA_KEY].toString()).tryParse();
190
190
  }
191
191
 
192
+ const text = match.metadata?.text as string | undefined;
193
+ delete match.metadata?.text; // delete the text metadata to avoid duplication in case we returned the default raw metadata
194
+
192
195
  matches.push({
193
196
  id: match.id,
194
197
  values: match.values,
195
- text: match.metadata?.text as string | undefined,
196
- metadata: match.metadata?.[this.USER_METADATA_KEY] as Record<string, any> | undefined,
198
+ text: text,
199
+ metadata: match.metadata?.[this.USER_METADATA_KEY] || match.metadata, // fallback to the default metadata if the user metadata is not present, this is for backward compatibility
197
200
  score: match.score,
198
201
  });
199
202
  }
@@ -207,7 +210,7 @@ export class PineconeVectorDB extends VectorDBConnector {
207
210
  acRequest: AccessRequest,
208
211
  namespace: string,
209
212
  sourceWrapper: IVectorDataSourceDto | IVectorDataSourceDto[]
210
- ): Promise<string[]> {
213
+ ): Promise<VectorDBResult[]> {
211
214
  //const teamId = await this.accountConnector.getCandidateTeam(acRequest.candidate);
212
215
  sourceWrapper = Array.isArray(sourceWrapper) ? sourceWrapper : [sourceWrapper];
213
216
 
@@ -239,7 +242,18 @@ export class PineconeVectorDB extends VectorDBConnector {
239
242
  await this.setACL(acRequest, namespace, acl);
240
243
  }
241
244
 
242
- return preparedSource.map((s) => s.id);
245
+ return preparedSource.map((s) => {
246
+ const { text, acl, user_metadata, ...restMetadata } = s.metadata || {};
247
+ return {
248
+ id: s.id,
249
+ values: s.values as number[],
250
+ text: text as string,
251
+ metadata: {
252
+ ...restMetadata,
253
+ ...((typeof user_metadata === 'string' ? JSON.parse(user_metadata) : user_metadata) as Record<string, any>),
254
+ },
255
+ };
256
+ });
243
257
  }
244
258
 
245
259
  @SecureConnector.AccessControl
@@ -265,7 +279,7 @@ export class PineconeVectorDB extends VectorDBConnector {
265
279
  const dsId = datasource.id || crypto.randomUUID();
266
280
 
267
281
  const formattedNs = this.constructNsName(acRequest.candidate as AccessCandidate, namespace);
268
- const chunkedText = chunkText(datasource.text, {
282
+ const chunkedText = this.embedder.chunkText(datasource.text, {
269
283
  chunkSize: datasource.chunkSize,
270
284
  chunkOverlap: datasource.chunkOverlap,
271
285
  });
@@ -294,9 +308,12 @@ export class PineconeVectorDB extends VectorDBConnector {
294
308
  name: datasource.label || 'Untitled',
295
309
  metadata: datasource.metadata ? jsonrepair(JSON.stringify(datasource.metadata)) : undefined,
296
310
  text: datasource.text,
297
- vectorIds: _vIds,
311
+ vectorIds: _vIds.map((v) => v.id),
298
312
  id: dsId,
299
313
  };
314
+ if (datasource.returnFullVectorInfo) {
315
+ dsData.vectorInfo = _vIds;
316
+ }
300
317
  // const url = `smythfs://${teamId}.team/_datasources/${dsId}.json`;
301
318
  // await SmythFS.Instance.write(url, JSON.stringify(dsData), AccessCandidate.team(teamId));
302
319
  await this.nkvConnector
@@ -12,6 +12,7 @@ import {
12
12
  IStorageVectorNamespace,
13
13
  IVectorDataSourceDto,
14
14
  QueryOptions,
15
+ VectorDBResult,
15
16
  VectorsResultData,
16
17
  } from '@sre/types/VectorDB.types';
17
18
  import { ConnectorService } from '@sre/Core/ConnectorsService';
@@ -21,7 +22,7 @@ import { OpenAIEmbeds } from '@sre/IO/VectorDB.service/embed/OpenAIEmbedding';
21
22
  import crypto from 'crypto';
22
23
  import { BaseEmbedding, TEmbeddings } from '../embed/BaseEmbedding';
23
24
  import { EmbeddingsFactory } from '../embed';
24
- import { chunkText } from '@sre/utils/string.utils';
25
+
25
26
  import { jsonrepair } from 'jsonrepair';
26
27
 
27
28
  const console = Logger('RAM VectorDB');
@@ -71,10 +72,10 @@ export class RAMVectorDB extends VectorDBConnector {
71
72
  this.accountConnector = ConnectorService.getAccountConnector();
72
73
 
73
74
  if (!_settings.embeddings) {
74
- _settings.embeddings = { provider: 'OpenAI', model: 'text-embedding-3-large', params: { dimensions: 1024 } };
75
+ _settings.embeddings = { provider: 'OpenAI', model: 'text-embedding-3-large', dimensions: 1024 };
75
76
  }
76
- if (!_settings.embeddings.params) _settings.embeddings.params = { dimensions: 1024 };
77
- if (!_settings.embeddings.params?.dimensions) _settings.embeddings.params.dimensions = 1024;
77
+
78
+ if (!_settings.embeddings.dimensions) _settings.embeddings.dimensions = 1024;
78
79
 
79
80
  this.embedder = EmbeddingsFactory.create(_settings.embeddings.provider, _settings.embeddings);
80
81
  }
@@ -225,7 +226,7 @@ export class RAMVectorDB extends VectorDBConnector {
225
226
  acRequest: AccessRequest,
226
227
  namespace: string,
227
228
  sourceWrapper: IVectorDataSourceDto | IVectorDataSourceDto[]
228
- ): Promise<string[]> {
229
+ ): Promise<VectorDBResult[]> {
229
230
  //const teamId = await this.accountConnector.getCandidateTeam(acRequest.candidate);
230
231
  const preparedNs = this.constructNsName(acRequest.candidate as AccessCandidate, namespace);
231
232
 
@@ -245,7 +246,7 @@ export class RAMVectorDB extends VectorDBConnector {
245
246
  RAMVectorDB.vectors[preparedNs] = [];
246
247
  }
247
248
 
248
- const insertedIds: string[] = [];
249
+ const insertedIds: VectorDBResult[] = [];
249
250
 
250
251
  for (const source of transformedSource) {
251
252
  const vectorData: VectorData = {
@@ -263,7 +264,18 @@ export class RAMVectorDB extends VectorDBConnector {
263
264
  RAMVectorDB.vectors[preparedNs].push(vectorData);
264
265
  }
265
266
 
266
- insertedIds.push(source.id);
267
+ const { text, acl, user_metadata, ...restMetadata } = source.metadata || {};
268
+
269
+ (insertedIds as VectorDBResult[]).push({
270
+ id: source.id,
271
+ values: source.source as number[],
272
+ text: text as string,
273
+ metadata: {
274
+ ...restMetadata,
275
+ ...((typeof user_metadata === 'string' ? JSON.parse(user_metadata) : user_metadata) as Record<string, any>),
276
+ },
277
+ });
278
+ //insertedIds.push(source.id);
267
279
  }
268
280
 
269
281
  return insertedIds;
@@ -303,7 +315,7 @@ export class RAMVectorDB extends VectorDBConnector {
303
315
  const dsId = datasource.id || crypto.randomUUID();
304
316
 
305
317
  const formattedNs = this.constructNsName(acRequest.candidate as AccessCandidate, namespace);
306
- const chunkedText = chunkText(datasource.text, {
318
+ const chunkedText = this.embedder.chunkText(datasource.text, {
307
319
  chunkSize: datasource.chunkSize,
308
320
  chunkOverlap: datasource.chunkOverlap,
309
321
  });
@@ -332,10 +344,14 @@ export class RAMVectorDB extends VectorDBConnector {
332
344
  name: datasource.label || 'Untitled',
333
345
  metadata: datasource.metadata ? jsonrepair(JSON.stringify(datasource.metadata)) : undefined,
334
346
  text: datasource.text,
335
- vectorIds: _vIds,
347
+ vectorIds: _vIds.map((v) => v.id),
336
348
  id: dsId,
337
349
  };
338
350
 
351
+ if (datasource.returnFullVectorInfo) {
352
+ dsData.vectorInfo = _vIds;
353
+ }
354
+
339
355
  // Store datasource metadata in memory
340
356
  if (!RAMVectorDB.datasources[formattedNs]) {
341
357
  RAMVectorDB.datasources[formattedNs] = {};
@@ -4,18 +4,21 @@ import { SupportedProviders, SupportedModels } from './index';
4
4
  import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
5
5
 
6
6
  export type TEmbeddings = {
7
- provider: SupportedProviders;
8
- model: SupportedModels[SupportedProviders];
7
+ provider?: SupportedProviders;
8
+ model?: SupportedModels[SupportedProviders];
9
9
 
10
10
  credentials?: {
11
11
  apiKey: string;
12
12
  };
13
- params?: {
14
- dimensions?: number;
15
- timeout?: number;
16
- chunkSize?: number;
17
- stripNewLines?: boolean;
18
- };
13
+
14
+ dimensions?: number;
15
+ timeout?: number;
16
+ chunkSize?: number;
17
+ chunkOverlap?: number;
18
+ batchSize?: number;
19
+ stripNewLines?: boolean;
20
+
21
+ params?: any;
19
22
  };
20
23
 
21
24
  type SupportedSources = 'text' | 'vector' | 'url';
@@ -24,16 +27,19 @@ export abstract class BaseEmbedding {
24
27
  model: string;
25
28
  modelName: string;
26
29
  chunkSize = 512;
30
+ chunkOverlap = 100;
27
31
  stripNewLines = true;
28
32
  dimensions?: number;
29
33
  timeout?: number;
34
+ batchSize = 10;
30
35
 
31
36
  constructor(fields?: Partial<TEmbeddings>) {
32
37
  this.model = fields?.model ?? this.model;
33
- this.chunkSize = fields?.params?.chunkSize ?? this.chunkSize;
34
- this.stripNewLines = fields?.params?.stripNewLines ?? this.stripNewLines;
35
- this.timeout = fields?.params?.timeout;
36
- this.dimensions = fields?.params?.dimensions;
38
+ this.chunkSize = fields?.chunkSize || fields?.params?.chunkSize || this.chunkSize;
39
+ this.chunkOverlap = fields?.chunkOverlap || fields?.params?.chunkOverlap || this.chunkOverlap;
40
+ this.stripNewLines = fields?.stripNewLines || fields?.params?.stripNewLines || this.stripNewLines;
41
+ this.timeout = fields?.timeout || fields?.params?.timeout;
42
+ this.dimensions = fields?.dimensions || fields?.params?.dimensions;
37
43
  }
38
44
 
39
45
  /**
@@ -58,6 +64,13 @@ export abstract class BaseEmbedding {
58
64
  }, [] as T[][]);
59
65
  }
60
66
 
67
+ public chunkText(text: string, { chunkSize, chunkOverlap }: { chunkSize?: number; chunkOverlap?: number }): string[] {
68
+ const textSplitter = new TextSplitter({
69
+ chunkSize: chunkSize || this.chunkSize,
70
+ chunkOverlap: chunkOverlap || this.chunkOverlap,
71
+ });
72
+ return textSplitter.splitText(text);
73
+ }
61
74
  /**
62
75
  * Utility method to process multiple texts based on stripNewLines setting
63
76
  */
@@ -105,3 +118,160 @@ export abstract class BaseEmbedding {
105
118
  .concat([1]);
106
119
  }
107
120
  }
121
+
122
+ class TextSplitter {
123
+ private chunkSize: number;
124
+ private chunkOverlap: number;
125
+ private separators: string[] = ['\n\n', '\n', ' ', ''];
126
+ private keepSeparator: boolean = true;
127
+
128
+ constructor({
129
+ chunkSize = 1000,
130
+ chunkOverlap = 200,
131
+ separators,
132
+ keepSeparator,
133
+ }: {
134
+ chunkSize?: number;
135
+ chunkOverlap?: number;
136
+ separators?: string[];
137
+ keepSeparator?: boolean;
138
+ } = {}) {
139
+ this.chunkSize = chunkSize;
140
+ this.chunkOverlap = chunkOverlap;
141
+
142
+ if (separators) {
143
+ this.separators = separators;
144
+ }
145
+
146
+ if (keepSeparator !== undefined) {
147
+ this.keepSeparator = keepSeparator;
148
+ }
149
+
150
+ if (this.chunkOverlap >= this.chunkSize) {
151
+ throw new Error('Cannot have chunkOverlap >= chunkSize');
152
+ }
153
+ }
154
+
155
+ public splitText(text: string): string[] {
156
+ return this._splitText(text, this.separators);
157
+ }
158
+
159
+ private _splitText(text: string, separators: string[]): string[] {
160
+ const finalChunks: string[] = [];
161
+
162
+ // Get appropriate separator to use
163
+ let separator: string = separators[separators.length - 1];
164
+ let newSeparators: string[] | undefined;
165
+
166
+ for (let i = 0; i < separators.length; i += 1) {
167
+ const s = separators[i];
168
+ if (s === '') {
169
+ separator = s;
170
+ break;
171
+ }
172
+ if (text.includes(s)) {
173
+ separator = s;
174
+ newSeparators = separators.slice(i + 1);
175
+ break;
176
+ }
177
+ }
178
+
179
+ // Split the text using the identified separator
180
+ const splits = this.splitOnSeparator(text, separator);
181
+
182
+ // Process splits, recursively splitting longer texts
183
+ let goodSplits: string[] = [];
184
+ const _separator = this.keepSeparator ? '' : separator;
185
+
186
+ for (const s of splits) {
187
+ if (this.lengthFunction(s) < this.chunkSize) {
188
+ goodSplits.push(s);
189
+ } else {
190
+ if (goodSplits.length) {
191
+ const mergedText = this.mergeSplits(goodSplits, _separator);
192
+ finalChunks.push(...mergedText);
193
+ goodSplits = [];
194
+ }
195
+
196
+ if (!newSeparators) {
197
+ finalChunks.push(s);
198
+ } else {
199
+ const otherInfo = this._splitText(s, newSeparators);
200
+ finalChunks.push(...otherInfo);
201
+ }
202
+ }
203
+ }
204
+
205
+ if (goodSplits.length) {
206
+ const mergedText = this.mergeSplits(goodSplits, _separator);
207
+ finalChunks.push(...mergedText);
208
+ }
209
+
210
+ return finalChunks;
211
+ }
212
+
213
+ private splitOnSeparator(text: string, separator: string): string[] {
214
+ let splits: string[];
215
+
216
+ if (separator) {
217
+ if (this.keepSeparator) {
218
+ const regexEscapedSeparator = separator.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&');
219
+ splits = text.split(new RegExp(`(?=${regexEscapedSeparator})`));
220
+ } else {
221
+ splits = text.split(separator);
222
+ }
223
+ } else {
224
+ splits = text.split('');
225
+ }
226
+
227
+ return splits.filter((s) => s !== '');
228
+ }
229
+
230
+ private lengthFunction(text: string): number {
231
+ return text.length;
232
+ }
233
+
234
+ private joinDocs(docs: string[], separator: string): string | null {
235
+ const text = docs.join(separator).trim();
236
+ return text === '' ? null : text;
237
+ }
238
+
239
+ private mergeSplits(splits: string[], separator: string): string[] {
240
+ const docs: string[] = [];
241
+ const currentDoc: string[] = [];
242
+ let total = 0;
243
+
244
+ for (const d of splits) {
245
+ const _len = this.lengthFunction(d);
246
+
247
+ if (total + _len + currentDoc.length * separator.length > this.chunkSize) {
248
+ if (total > this.chunkSize) {
249
+ console.warn(`Created a chunk of size ${total}, which is longer than the specified ${this.chunkSize}`);
250
+ }
251
+
252
+ if (currentDoc.length > 0) {
253
+ const doc = this.joinDocs(currentDoc, separator);
254
+ if (doc !== null) {
255
+ docs.push(doc);
256
+ }
257
+
258
+ // Keep popping if conditions are met
259
+ while (total > this.chunkOverlap || (total + _len + currentDoc.length * separator.length > this.chunkSize && total > 0)) {
260
+ total -= this.lengthFunction(currentDoc[0]);
261
+ currentDoc.shift();
262
+ }
263
+ }
264
+ }
265
+
266
+ currentDoc.push(d);
267
+ total += _len;
268
+ }
269
+
270
+ const doc = this.joinDocs(currentDoc, separator);
271
+ if (doc !== null) {
272
+ docs.push(doc);
273
+ }
274
+
275
+ return docs;
276
+ }
277
+ }
@@ -18,7 +18,7 @@ export class GoogleEmbeds extends BaseEmbedding {
18
18
  }
19
19
 
20
20
  async embedTexts(texts: string[], candidate: AccessCandidate): Promise<number[][]> {
21
- const batches = this.chunkArr(this.processTexts(texts), this.chunkSize);
21
+ const batches = this.chunkArr(this.processTexts(texts), this.batchSize);
22
22
 
23
23
  const batchRequests = batches.map((batch) => {
24
24
  return this.embed(batch, candidate);
@@ -41,7 +41,7 @@ export class OpenAIEmbeds extends BaseEmbedding {
41
41
  }
42
42
 
43
43
  async embedTexts(texts: string[], candidate: AccessCandidate): Promise<number[][]> {
44
- const batches = this.chunkArr(this.processTexts(texts), this.chunkSize);
44
+ const batches = this.chunkArr(this.processTexts(texts), this.batchSize);
45
45
 
46
46
  const batchRequests = batches.map((batch) => {
47
47
  const params: OpenAIClient.EmbeddingCreateParams = {
@@ -1,6 +1,7 @@
1
1
  import { OpenAIEmbeds } from './OpenAIEmbedding';
2
2
  import { GoogleEmbeds } from './GoogleEmbedding';
3
3
  import { TEmbeddings } from './BaseEmbedding';
4
+ import { TLLMModel } from '@sre/types/LLM.types';
4
5
 
5
6
  // a factory to get the correct embedding provider based on the provider name
6
7
  const supportedProviders = {
@@ -20,7 +21,16 @@ export type SupportedModels = {
20
21
  };
21
22
 
22
23
  export class EmbeddingsFactory {
23
- public static create(provider: SupportedProviders, config: TEmbeddings) {
24
- return new supportedProviders[provider].embedder(config);
24
+ public static create(provider?: SupportedProviders, config?: TEmbeddings & { model?: SupportedModels[SupportedProviders] | TLLMModel }) {
25
+ if (!provider) provider = 'OpenAI';
26
+ if (!config) config = { provider: 'OpenAI', model: 'text-embedding-3-large', dimensions: 1024 };
27
+
28
+ //if the model is a TLLMModel, we need to convert it to a SupportedModels[SupportedProviders]
29
+ if (config.model && typeof config.model === 'object') {
30
+ provider = (config.model as TLLMModel).provider as SupportedProviders;
31
+ config.model = (config.model as TLLMModel).modelId;
32
+ }
33
+
34
+ return new supportedProviders[provider as SupportedProviders].embedder(config);
25
35
  }
26
36
  }