diff --git a/src/public/app/widgets/type_widgets/options/ai_settings.ts b/src/public/app/widgets/type_widgets/options/ai_settings.ts index 3563ff07c..de76f5de3 100644 --- a/src/public/app/widgets/type_widgets/options/ai_settings.ts +++ b/src/public/app/widgets/type_widgets/options/ai_settings.ts @@ -238,6 +238,13 @@ export default class AiSettingsWidget extends OptionsWidget {
${t("ai_llm.reprocess_all_embeddings_description")}
+
+ +
${t("ai_llm.reprocess_index_description")}
+
+
@@ -461,6 +468,25 @@ export default class AiSettingsWidget extends OptionsWidget { } }); + const $reprocessIndex = this.$widget.find('.reprocess-index'); + $reprocessIndex.on('click', async () => { + $reprocessIndex.prop('disabled', true); + $reprocessIndex.text(t("ai_llm.reprocessing_index")); + + try { + await server.post('embeddings/rebuild-index'); + toastService.showMessage(t("ai_llm.reprocess_index_started")); + // Refresh stats after reprocessing starts + await this.refreshEmbeddingStats(); + } catch (error) { + console.error("Error rebuilding index:", error); + toastService.showError(t("ai_llm.reprocess_index_error")); + } finally { + $reprocessIndex.prop('disabled', false); + $reprocessIndex.text(t("ai_llm.reprocess_index")); + } + }); + const $embeddingRefreshStats = this.$widget.find('.embedding-refresh-stats'); $embeddingRefreshStats.on('click', async () => { await this.refreshEmbeddingStats(); diff --git a/src/public/translations/en/translation.json b/src/public/translations/en/translation.json index 9d675a234..b68881c1c 100644 --- a/src/public/translations/en/translation.json +++ b/src/public/translations/en/translation.json @@ -1161,6 +1161,7 @@ "enable_auto_update_embeddings_description": "Automatically update embeddings when notes are modified", "auto_update_embeddings": "Auto-update Embeddings", "auto_update_embeddings_desc": "Automatically update embeddings when notes are modified", + "no_failed_embeddings": "No failed embeddings", "enable_automatic_indexing": "Automatic Indexing", "enable_automatic_indexing_description": "Periodically run indexing jobs in the background to maintain the knowledge base", "similarity_threshold": "Similarity Threshold", @@ -1179,6 +1180,12 @@ "reprocess_started": "Embedding reprocessing started in the background", "reprocess_error": "Error starting embedding reprocessing", + "reprocess_index": "Rebuild Search Index", + "reprocess_index_description": "Rebuild the semantic search index structure for better query performance. This doesn't regenerate embeddings.", + "reprocessing_index": "Rebuilding...", + "reprocess_index_started": "Index rebuilding started in the background", + "reprocess_index_error": "Error rebuilding search index", + "embedding_statistics": "Embedding Statistics", "total_notes": "Total Notes", "processed_notes": "Processed Notes", diff --git a/src/routes/api/embeddings.ts b/src/routes/api/embeddings.ts index 061bfecd6..d1194a1ec 100644 --- a/src/routes/api/embeddings.ts +++ b/src/routes/api/embeddings.ts @@ -1,6 +1,7 @@ import options from "../../services/options.js"; import vectorStore from "../../services/llm/embeddings/vector_store.js"; import providerManager from "../../services/llm/embeddings/providers.js"; +import indexService from "../../services/llm/index_service.js"; import becca from "../../becca/becca.js"; import type { Request, Response } from "express"; import log from "../../services/log.js"; @@ -257,6 +258,27 @@ async function retryAllFailedNotes(req: Request, res: Response) { }; } +/** + * Manually trigger a rebuild of the search index + */ +async function rebuildIndex(req: Request, res: Response) { + // Start the index rebuilding operation in the background + setTimeout(async () => { + try { + await indexService.startFullIndexing(true); + log.info("Index rebuilding completed successfully"); + } catch (error: any) { + log.error(`Error during background index rebuilding: ${error.message || "Unknown error"}`); + } + }, 0); + + // Return the response data + return { + success: true, + message: "Index rebuilding started in the background" + }; +} + export default { findSimilarNotes, searchByText, @@ -267,5 +289,6 @@ export default { getEmbeddingStats, getFailedNotes, retryFailedNote, - retryAllFailedNotes + retryAllFailedNotes, + rebuildIndex }; diff --git a/src/routes/routes.ts b/src/routes/routes.ts index 88bb02d9b..251544817 100644 --- a/src/routes/routes.ts +++ b/src/routes/routes.ts @@ -383,6 +383,7 @@ function register(app: express.Application) { apiRoute(GET, "/api/embeddings/failed", embeddingsRoute.getFailedNotes); apiRoute(PST, "/api/embeddings/retry/:noteId", embeddingsRoute.retryFailedNote); apiRoute(PST, "/api/embeddings/retry-all-failed", embeddingsRoute.retryAllFailedNotes); + apiRoute(PST, "/api/embeddings/rebuild-index", embeddingsRoute.rebuildIndex); // LLM chat session management endpoints apiRoute(PST, "/api/llm/sessions", llmRoute.createSession); @@ -392,7 +393,7 @@ function register(app: express.Application) { apiRoute(DEL, "/api/llm/sessions/:sessionId", llmRoute.deleteSession); apiRoute(PST, "/api/llm/sessions/:sessionId/messages", llmRoute.sendMessage); route(GET, "/api/llm/sessions/:sessionId/messages", [auth.checkApiAuth, csrfMiddleware], llmRoute.sendMessage, apiResultHandler); - + // LLM index management endpoints apiRoute(GET, "/api/llm/index/stats", llmRoute.getIndexStats); apiRoute(PST, "/api/llm/index/start", llmRoute.startIndexing);