diff --git a/main.js b/main.js index 95ac664..8bc6351 100644 --- a/main.js +++ b/main.js @@ -8004,7 +8004,7 @@ var SemanticCacheService = class _SemanticCacheService { async clearCache() { if (!this.config.enabled || !this.client) return; try { - await this.client.reset(); + await this.client.deleteCollection({ name: this.config.collectionName }); Logger.info("Semantic cache cleared", "semantic-cache"); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); @@ -9448,31 +9448,54 @@ var ContentVectorizer = class { this.fetchFn = fetchFn ?? ((url, init) => fetch(url, init)); } /** - * Generates embeddings for a content chunk + * Generates embeddings for a content chunk with retry logic */ async vectorize(chunk) { - try { - const prompt = this.createPrompt(chunk); - const response = await this.fetchFn(`${this.ollamaUrl}/api/embeddings`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - model: this.model, - prompt - }) - }); - if (!response.ok) { - throw new Error(`Embedding failed with status ${response.status}`); + const prompt = this.createPrompt(chunk); + const maxRetries = 3; + const baseDelay = 1e3; + for (let attempt = 0; attempt < maxRetries; attempt++) { + try { + if (attempt > 0) { + const delay = baseDelay * Math.pow(2, attempt - 1); + Logger.info( + `Retrying embedding (attempt ${attempt + 1}/${maxRetries}) after ${delay}ms`, + "indexing-pipeline" + ); + await new Promise((resolve) => setTimeout(resolve, delay)); + } + const response = await this.fetchFn(`${this.ollamaUrl}/api/embeddings`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + model: this.model, + prompt + }) + }); + if (!response.ok) { + throw new Error(`Embedding failed with status ${response.status}`); + } + const data = await response.json(); + if (!this.isEmbeddingResponse(data)) { + throw new Error("Invalid embedding response"); + } + return data.embedding; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + Logger.warn( + `Embedding attempt ${attempt + 1} failed: ${errorMessage}`, + "indexing-pipeline" + ); + if (attempt === maxRetries - 1) { + Logger.warn( + `Failed to generate embedding after ${maxRetries} attempts`, + "indexing-pipeline" + ); + return []; + } } - const data = await response.json(); - if (!this.isEmbeddingResponse(data)) { - throw new Error("Invalid embedding response"); - } - return data.embedding; - } catch (error) { - Logger.warn(`Failed to generate embedding: ${String(error)}`, "indexing-pipeline"); - return []; } + return []; } isEmbeddingResponse(data) { return typeof data === "object" && data !== null && Array.isArray(data.embedding) && data.embedding.every((value) => typeof value === "number"); @@ -10010,8 +10033,8 @@ var OllamaPlugin = class extends import_obsidian4.Plugin { const files = this.app.vault.getMarkdownFiles(); Logger.info(`Starting background vault indexing for ${files.length} files...`, "main"); let indexed = 0; - const BATCH_SIZE = 5; - const DELAY_MS = 100; + const BATCH_SIZE = 2; + const DELAY_MS = 500; for (let i = 0; i < files.length; i += BATCH_SIZE) { if (signal.aborted) { Logger.info("Vault indexing cancelled.", "main"); diff --git a/src/indexing-pipeline/vectorization.ts b/src/indexing-pipeline/vectorization.ts index 62612c0..fbbd2e1 100644 --- a/src/indexing-pipeline/vectorization.ts +++ b/src/indexing-pipeline/vectorization.ts @@ -23,36 +23,60 @@ export class ContentVectorizer { } /** - * Generates embeddings for a content chunk + * Generates embeddings for a content chunk with retry logic */ async vectorize(chunk: ContentChunk): Promise { - try { - const prompt = this.createPrompt(chunk); + const prompt = this.createPrompt(chunk); + const maxRetries = 3; + const baseDelay = 1000; - const response = await this.fetchFn(`${this.ollamaUrl}/api/embeddings`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - model: this.model, - prompt: prompt, - }), - }); + for (let attempt = 0; attempt < maxRetries; attempt++) { + try { + if (attempt > 0) { + const delay = baseDelay * Math.pow(2, attempt - 1); + Logger.info( + `Retrying embedding (attempt ${attempt + 1}/${maxRetries}) after ${delay}ms`, + 'indexing-pipeline' + ); + await new Promise((resolve) => setTimeout(resolve, delay)); + } - if (!response.ok) { - throw new Error(`Embedding failed with status ${response.status}`); + const response = await this.fetchFn(`${this.ollamaUrl}/api/embeddings`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + model: this.model, + prompt: prompt, + }), + }); + + if (!response.ok) { + throw new Error(`Embedding failed with status ${response.status}`); + } + + const data: unknown = await response.json(); + if (!this.isEmbeddingResponse(data)) { + throw new Error('Invalid embedding response'); + } + + return data.embedding; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + Logger.warn( + `Embedding attempt ${attempt + 1} failed: ${errorMessage}`, + 'indexing-pipeline' + ); + if (attempt === maxRetries - 1) { + Logger.warn( + `Failed to generate embedding after ${maxRetries} attempts`, + 'indexing-pipeline' + ); + return []; + } } - - const data: unknown = await response.json(); - if (!this.isEmbeddingResponse(data)) { - throw new Error('Invalid embedding response'); - } - - return data.embedding; - } catch (error) { - // Return empty array on failure to maintain compatibility - Logger.warn(`Failed to generate embedding: ${String(error)}`, 'indexing-pipeline'); - return []; } + + return []; } private isEmbeddingResponse(data: unknown): data is { embedding: number[] } { diff --git a/src/main.ts b/src/main.ts index bd17e90..2550640 100755 --- a/src/main.ts +++ b/src/main.ts @@ -166,8 +166,8 @@ export default class OllamaPlugin extends Plugin { Logger.info(`Starting background vault indexing for ${files.length} files...`, 'main'); let indexed = 0; - const BATCH_SIZE = 5; - const DELAY_MS = 100; + const BATCH_SIZE = 2; + const DELAY_MS = 500; for (let i = 0; i < files.length; i += BATCH_SIZE) { if (signal.aborted) { @@ -191,7 +191,7 @@ export default class OllamaPlugin extends Plugin { }) ); - // Small delay between batches to avoid overloading Ollama + // Delay between batches to avoid overloading Ollama if (i + BATCH_SIZE < files.length) { await new Promise((resolve) => setTimeout(resolve, DELAY_MS)); } diff --git a/src/semantic-cache.ts b/src/semantic-cache.ts index d0a03b5..4e6eb72 100644 --- a/src/semantic-cache.ts +++ b/src/semantic-cache.ts @@ -92,7 +92,7 @@ export class SemanticCacheService { if (!this.config.enabled || !this.client) return; try { - await this.client.reset(); + await this.client.deleteCollection({ name: this.config.collectionName }); Logger.info('Semantic cache cleared', 'semantic-cache'); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); diff --git a/tests/semantic-cache.test.ts b/tests/semantic-cache.test.ts index 5f3c4cf..232b7f3 100644 --- a/tests/semantic-cache.test.ts +++ b/tests/semantic-cache.test.ts @@ -155,13 +155,15 @@ describe('SemanticCacheService', () => { await disabledCacheService.clearCache(); - expect(mockChromaClient.reset).not.toHaveBeenCalled(); + expect(mockChromaClient.deleteCollection).not.toHaveBeenCalled(); }); - it('should clear the cache via the ChromaClient', async () => { + it('should clear the cache via deleteCollection', async () => { await cacheService.clearCache(); - expect(mockChromaClient.reset).toHaveBeenCalled(); + expect(mockChromaClient.deleteCollection).toHaveBeenCalledWith({ + name: mockCacheConfig.collectionName, + }); }); }); });