doc2vec 2.4.0 → 2.5.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/README.md CHANGED
@@ -145,6 +145,9 @@ Configuration is managed through two files:
145
145
  OPENAI_API_KEY="sk-..."
146
146
  OPENAI_MODEL="text-embedding-3-large" # Optional, defaults to text-embedding-3-large
147
147
 
148
+ # Optional: Embedding dimension size (defaults to 3072)
149
+ EMBEDDING_DIMENSION="3072"
150
+
148
151
  # Required: Your Azure OpenAI credentials (if using Azure provider)
149
152
  AZURE_OPENAI_KEY="your-azure-key"
150
153
  AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com"
@@ -223,6 +226,10 @@ Configuration is managed through two files:
223
226
  * `qdrant_port`: (Optional) Port for the Qdrant REST API. Defaults to `443` if `qdrant_url` starts with `https`, otherwise `6333`.
224
227
  * `collection_name`: (Optional) Name of the Qdrant collection to use. Defaults to `<product_name>_<version>` (lowercased, spaces replaced with underscores).
225
228
 
229
+ Optional embedding configuration:
230
+ * `embedding.provider`: Provider for embeddings (`openai` or `azure`).
231
+ * `embedding.dimension`: Embedding vector size. Defaults to `3072` when not set.
232
+
226
233
  **Example (`config.yaml`):**
227
234
  ```yaml
228
235
  # Optional: Configure embedding provider
@@ -230,6 +237,7 @@ Configuration is managed through two files:
230
237
  # Defaults to OpenAI if not specified
231
238
  embedding:
232
239
  provider: 'openai' # or 'azure'
240
+ dimension: 3072 # Optional, defaults to 3072
233
241
  openai:
234
242
  api_key: '${OPENAI_API_KEY}' # Optional, uses env var by default
235
243
  model: 'text-embedding-3-large' # Optional, defaults to text-embedding-3-large
@@ -586,7 +586,7 @@ class ContentProcessor {
586
586
  logger.debug(`Finding links on page ${url}`);
587
587
  let newLinksFound = 0;
588
588
  for (const href of result.links) {
589
- const fullUrl = utils_1.Utils.buildUrl(href, pageUrlForLinks);
589
+ const fullUrl = utils_1.Utils.buildUrl(href, pageUrlForLinks, logger);
590
590
  if (fullUrl.startsWith(sourceConfig.url)) {
591
591
  addReferrer(fullUrl, pageUrlForLinks);
592
592
  if (!visitedUrls.has(utils_1.Utils.normalizeUrl(fullUrl))) {
package/dist/database.js CHANGED
@@ -44,7 +44,7 @@ const sqliteVec = __importStar(require("sqlite-vec"));
44
44
  const js_client_rest_1 = require("@qdrant/js-client-rest");
45
45
  const utils_1 = require("./utils");
46
46
  class DatabaseManager {
47
- static async initDatabase(config, parentLogger) {
47
+ static async initDatabase(config, parentLogger, embeddingDimension) {
48
48
  const logger = parentLogger.child('database');
49
49
  const dbConfig = config.database_config;
50
50
  if (dbConfig.type === 'sqlite') {
@@ -53,10 +53,10 @@ class DatabaseManager {
53
53
  logger.info(`Opening SQLite database at ${dbPath}`);
54
54
  const db = new better_sqlite3_1.default(dbPath, { allowExtension: true });
55
55
  sqliteVec.load(db);
56
- logger.debug(`Creating vec_items table if it doesn't exist`);
56
+ logger.debug(`Creating vec_items table if it doesn't exist (dimension: ${embeddingDimension})`);
57
57
  db.exec(`
58
58
  CREATE VIRTUAL TABLE IF NOT EXISTS vec_items USING vec0(
59
- embedding FLOAT[3072],
59
+ embedding FLOAT[${embeddingDimension}],
60
60
  product_name TEXT,
61
61
  version TEXT,
62
62
  branch TEXT,
@@ -81,7 +81,7 @@ class DatabaseManager {
81
81
  const collectionName = params.collection_name || `${config.product_name.toLowerCase().replace(/\s+/g, '_')}_${config.version}`;
82
82
  logger.info(`Connecting to Qdrant at ${qdrantUrl}:${qdrantPort}, collection: ${collectionName}`);
83
83
  const qdrantClient = new js_client_rest_1.QdrantClient({ url: qdrantUrl, apiKey: process.env.QDRANT_API_KEY, port: qdrantPort });
84
- await this.createCollectionQdrant(qdrantClient, collectionName, logger);
84
+ await this.createCollectionQdrant(qdrantClient, collectionName, logger, embeddingDimension);
85
85
  logger.info(`Qdrant connection established successfully`);
86
86
  return { client: qdrantClient, collectionName, type: 'qdrant' };
87
87
  }
@@ -91,7 +91,7 @@ class DatabaseManager {
91
91
  throw new Error(errMsg);
92
92
  }
93
93
  }
94
- static async createCollectionQdrant(qdrantClient, collectionName, logger) {
94
+ static async createCollectionQdrant(qdrantClient, collectionName, logger, embeddingDimension) {
95
95
  try {
96
96
  logger.debug(`Checking if collection ${collectionName} exists`);
97
97
  const collections = await qdrantClient.getCollections();
@@ -100,10 +100,10 @@ class DatabaseManager {
100
100
  logger.info(`Collection ${collectionName} already exists`);
101
101
  return;
102
102
  }
103
- logger.info(`Creating new collection ${collectionName}`);
103
+ logger.info(`Creating new collection ${collectionName} with dimension ${embeddingDimension}`);
104
104
  await qdrantClient.createCollection(collectionName, {
105
105
  vectors: {
106
- size: 3072,
106
+ size: embeddingDimension,
107
107
  distance: "Cosine",
108
108
  },
109
109
  });
@@ -181,7 +181,7 @@ class DatabaseManager {
181
181
  }
182
182
  return defaultValue;
183
183
  }
184
- static async setMetadataValue(dbConnection, key, value, logger) {
184
+ static async setMetadataValue(dbConnection, key, value, logger, embeddingDimension) {
185
185
  try {
186
186
  if (dbConnection.type === 'sqlite') {
187
187
  const stmt = dbConnection.db.prepare(`
@@ -193,8 +193,7 @@ class DatabaseManager {
193
193
  }
194
194
  else if (dbConnection.type === 'qdrant') {
195
195
  const metadataUUID = utils_1.Utils.generateMetadataUUID(key);
196
- const dummyEmbeddingSize = 3072;
197
- const dummyEmbedding = new Array(dummyEmbeddingSize).fill(0);
196
+ const dummyEmbedding = new Array(embeddingDimension).fill(0);
198
197
  const metadataPoint = {
199
198
  id: metadataUUID,
200
199
  vector: dummyEmbedding,
@@ -258,7 +257,7 @@ class DatabaseManager {
258
257
  logger.info(`No saved run date found for ${repo}, using default: ${defaultDate}`);
259
258
  return defaultDate;
260
259
  }
261
- static async updateLastRunDate(dbConnection, repo, logger) {
260
+ static async updateLastRunDate(dbConnection, repo, logger, embeddingDimension) {
262
261
  const now = new Date().toISOString();
263
262
  try {
264
263
  if (dbConnection.type === 'sqlite') {
@@ -276,8 +275,7 @@ class DatabaseManager {
276
275
  const metadataKey = `last_run_${repo.replace('/', '_')}`;
277
276
  logger.debug(`Using UUID: ${metadataUUID} for metadata`);
278
277
  // Generate a dummy embedding (all zeros)
279
- const dummyEmbeddingSize = 3072; // Same size as your content embeddings
280
- const dummyEmbedding = new Array(dummyEmbeddingSize).fill(0);
278
+ const dummyEmbedding = new Array(embeddingDimension).fill(0);
281
279
  // Create a point with special metadata payload
282
280
  const metadataPoint = {
283
281
  id: metadataUUID,
package/dist/doc2vec.js CHANGED
@@ -72,6 +72,7 @@ class Doc2Vec {
72
72
  // Check environment variable if not specified in config
73
73
  const embeddingProvider = this.config.embedding?.provider || process.env.EMBEDDING_PROVIDER || 'openai';
74
74
  const embeddingConfig = this.config.embedding || { provider: embeddingProvider };
75
+ this.embeddingDimension = this.resolveEmbeddingDimension(embeddingConfig);
75
76
  if (embeddingProvider === 'azure') {
76
77
  const azureApiKey = embeddingConfig.azure?.api_key || process.env.AZURE_OPENAI_KEY;
77
78
  const azureEndpoint = embeddingConfig.azure?.endpoint || process.env.AZURE_OPENAI_ENDPOINT;
@@ -88,7 +89,7 @@ class Doc2Vec {
88
89
  apiVersion: azureApiVersion,
89
90
  });
90
91
  this.embeddingModel = azureDeploymentName;
91
- this.logger.info(`Using Azure OpenAI with deployment: ${azureDeploymentName}`);
92
+ this.logger.info(`Using Azure OpenAI with deployment: ${azureDeploymentName} (${this.embeddingDimension} dimensions)`);
92
93
  }
93
94
  else {
94
95
  const openaiApiKey = embeddingConfig.openai?.api_key || process.env.OPENAI_API_KEY;
@@ -99,7 +100,7 @@ class Doc2Vec {
99
100
  }
100
101
  this.openai = new openai_1.OpenAI({ apiKey: openaiApiKey });
101
102
  this.embeddingModel = openaiModel;
102
- this.logger.info(`Using OpenAI with model: ${openaiModel}`);
103
+ this.logger.info(`Using OpenAI with model: ${openaiModel} (${this.embeddingDimension} dimensions)`);
103
104
  }
104
105
  this.contentProcessor = new content_processor_1.ContentProcessor(this.logger);
105
106
  }
@@ -144,6 +145,21 @@ class Doc2Vec {
144
145
  process.exit(1);
145
146
  }
146
147
  }
148
+ resolveEmbeddingDimension(embeddingConfig) {
149
+ const defaultDimension = 3072;
150
+ const rawConfigValue = embeddingConfig?.dimension;
151
+ const rawEnvValue = process.env.EMBEDDING_DIMENSION;
152
+ const candidate = rawConfigValue ?? (rawEnvValue ? Number(rawEnvValue) : undefined);
153
+ if (candidate === undefined) {
154
+ return defaultDimension;
155
+ }
156
+ const parsedValue = typeof candidate === 'string' ? Number(candidate) : candidate;
157
+ if (!Number.isFinite(parsedValue) || parsedValue <= 0 || !Number.isInteger(parsedValue)) {
158
+ this.logger.warn(`Invalid embedding dimension provided (${candidate}), falling back to ${defaultDimension}`);
159
+ return defaultDimension;
160
+ }
161
+ return parsedValue;
162
+ }
147
163
  async run() {
148
164
  this.logger.section('PROCESSING SOURCES');
149
165
  for (const sourceConfig of this.config.sources) {
@@ -373,13 +389,13 @@ class Doc2Vec {
373
389
  await processIssue(issues[i]);
374
390
  }
375
391
  // Update the last run date in the database after processing all issues
376
- await database_1.DatabaseManager.updateLastRunDate(dbConnection, repo, logger);
392
+ await database_1.DatabaseManager.updateLastRunDate(dbConnection, repo, logger, this.embeddingDimension);
377
393
  logger.info(`Successfully processed ${issues.length} issues`);
378
394
  }
379
395
  async processGithubRepo(config, parentLogger) {
380
396
  const logger = parentLogger.child('process');
381
397
  logger.info(`Starting processing for GitHub repo: ${config.repo}`);
382
- const dbConnection = await database_1.DatabaseManager.initDatabase(config, logger);
398
+ const dbConnection = await database_1.DatabaseManager.initDatabase(config, logger, this.embeddingDimension);
383
399
  // Initialize metadata storage
384
400
  await database_1.DatabaseManager.initDatabaseMetadata(dbConnection, logger);
385
401
  logger.section('GITHUB ISSUES');
@@ -390,7 +406,7 @@ class Doc2Vec {
390
406
  async processWebsite(config, parentLogger) {
391
407
  const logger = parentLogger.child('process');
392
408
  logger.info(`Starting processing for website: ${config.url}`);
393
- const dbConnection = await database_1.DatabaseManager.initDatabase(config, logger);
409
+ const dbConnection = await database_1.DatabaseManager.initDatabase(config, logger, this.embeddingDimension);
394
410
  await database_1.DatabaseManager.initDatabaseMetadata(dbConnection, logger);
395
411
  const validChunkIds = new Set();
396
412
  const visitedUrls = new Set();
@@ -420,7 +436,7 @@ class Doc2Vec {
420
436
  return database_1.DatabaseManager.getMetadataValue(dbConnection, `etag:${url}`, undefined, logger);
421
437
  },
422
438
  set: async (url, etag) => {
423
- await database_1.DatabaseManager.setMetadataValue(dbConnection, `etag:${url}`, etag, logger);
439
+ await database_1.DatabaseManager.setMetadataValue(dbConnection, `etag:${url}`, etag, logger, this.embeddingDimension);
424
440
  },
425
441
  };
426
442
  const lastmodStore = {
@@ -428,7 +444,7 @@ class Doc2Vec {
428
444
  return database_1.DatabaseManager.getMetadataValue(dbConnection, `lastmod:${url}`, undefined, logger);
429
445
  },
430
446
  set: async (url, lastmod) => {
431
- await database_1.DatabaseManager.setMetadataValue(dbConnection, `lastmod:${url}`, lastmod, logger);
447
+ await database_1.DatabaseManager.setMetadataValue(dbConnection, `lastmod:${url}`, lastmod, logger, this.embeddingDimension);
432
448
  },
433
449
  };
434
450
  const crawlResult = await this.contentProcessor.crawlWebsite(config.url, config, async (url, content) => {
@@ -502,7 +518,7 @@ class Doc2Vec {
502
518
  async processLocalDirectory(config, parentLogger) {
503
519
  const logger = parentLogger.child('process');
504
520
  logger.info(`Starting processing for local directory: ${config.path}`);
505
- const dbConnection = await database_1.DatabaseManager.initDatabase(config, logger);
521
+ const dbConnection = await database_1.DatabaseManager.initDatabase(config, logger, this.embeddingDimension);
506
522
  const validChunkIds = new Set();
507
523
  const processedFiles = new Set();
508
524
  logger.section('FILE SCANNING AND EMBEDDING');
@@ -560,7 +576,7 @@ class Doc2Vec {
560
576
  async processCodeSource(config, parentLogger) {
561
577
  const logger = parentLogger.child('process');
562
578
  logger.info(`Starting processing for code source (${config.source})`);
563
- const dbConnection = await database_1.DatabaseManager.initDatabase(config, logger);
579
+ const dbConnection = await database_1.DatabaseManager.initDatabase(config, logger, this.embeddingDimension);
564
580
  const validChunkIds = new Set();
565
581
  const processedFiles = new Set();
566
582
  let basePath;
@@ -692,10 +708,10 @@ class Doc2Vec {
692
708
  await database_1.DatabaseManager.removeChunksByUrlQdrant(dbConnection, url, logger);
693
709
  }
694
710
  }
695
- await database_1.DatabaseManager.setMetadataValue(dbConnection, fileListKey, JSON.stringify(currentList), logger);
711
+ await database_1.DatabaseManager.setMetadataValue(dbConnection, fileListKey, JSON.stringify(currentList), logger, this.embeddingDimension);
696
712
  if (lastMtimeKey) {
697
713
  const nextMtime = maxObservedMtime > 0 ? maxObservedMtime : Date.now();
698
- await database_1.DatabaseManager.setMetadataValue(dbConnection, lastMtimeKey, `${nextMtime}`, logger);
714
+ await database_1.DatabaseManager.setMetadataValue(dbConnection, lastMtimeKey, `${nextMtime}`, logger, this.embeddingDimension);
699
715
  }
700
716
  }
701
717
  }
@@ -713,7 +729,7 @@ class Doc2Vec {
713
729
  const headSha = await this.getRepoHeadSha(basePath, logger);
714
730
  if (headSha) {
715
731
  const shaKey = this.buildCodeShaMetadataKey(config.repo, repoBranch);
716
- await database_1.DatabaseManager.setMetadataValue(dbConnection, shaKey, headSha, logger);
732
+ await database_1.DatabaseManager.setMetadataValue(dbConnection, shaKey, headSha, logger, this.embeddingDimension);
717
733
  }
718
734
  }
719
735
  if (tempDir) {
@@ -876,7 +892,7 @@ class Doc2Vec {
876
892
  async processZendesk(config, parentLogger) {
877
893
  const logger = parentLogger.child('process');
878
894
  logger.info(`Starting processing for Zendesk: ${config.zendesk_subdomain}.zendesk.com`);
879
- const dbConnection = await database_1.DatabaseManager.initDatabase(config, logger);
895
+ const dbConnection = await database_1.DatabaseManager.initDatabase(config, logger, this.embeddingDimension);
880
896
  // Initialize metadata storage
881
897
  await database_1.DatabaseManager.initDatabaseMetadata(dbConnection, logger);
882
898
  const fetchTickets = config.fetch_tickets !== false; // default true
@@ -1051,7 +1067,7 @@ class Doc2Vec {
1051
1067
  }
1052
1068
  }
1053
1069
  // Update the last run date in the database
1054
- await database_1.DatabaseManager.updateLastRunDate(dbConnection, `zendesk_tickets_${config.zendesk_subdomain}`, logger);
1070
+ await database_1.DatabaseManager.updateLastRunDate(dbConnection, `zendesk_tickets_${config.zendesk_subdomain}`, logger, this.embeddingDimension);
1055
1071
  logger.info(`Successfully processed ${totalTickets} tickets`);
1056
1072
  }
1057
1073
  async fetchAndProcessZendeskArticles(config, dbConnection, logger) {
package/dist/utils.js CHANGED
@@ -69,12 +69,14 @@ class Utils {
69
69
  return url;
70
70
  }
71
71
  }
72
- static buildUrl(href, currentUrl) {
72
+ static buildUrl(href, currentUrl, logger) {
73
73
  try {
74
74
  return new URL(href, currentUrl).toString();
75
75
  }
76
76
  catch (error) {
77
- console.warn(`Invalid URL found: ${href}`);
77
+ if (logger) {
78
+ logger.warn(`Invalid URL found: ${href}`);
79
+ }
78
80
  return '';
79
81
  }
80
82
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doc2vec",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "type": "commonjs",
5
5
  "description": "",
6
6
  "main": "dist/doc2vec.js",