From 1690217797de000d0feb6fdbe0f77557f3e5a263 Mon Sep 17 00:00:00 2001 From: perf3ct Date: Tue, 1 Apr 2025 10:55:20 -0700 Subject: [PATCH] update LLM API endpoints --- .../options/ai_settings/providers.ts | 48 +- src/routes/api/llm.ts | 749 ++++++++---------- src/routes/api/ollama.ts | 28 +- src/routes/routes.ts | 30 +- 4 files changed, 386 insertions(+), 469 deletions(-) diff --git a/src/public/app/widgets/type_widgets/options/ai_settings/providers.ts b/src/public/app/widgets/type_widgets/options/ai_settings/providers.ts index 2488f9ed3..c3b35e34d 100644 --- a/src/public/app/widgets/type_widgets/options/ai_settings/providers.ts +++ b/src/public/app/widgets/type_widgets/options/ai_settings/providers.ts @@ -2,14 +2,14 @@ import server from "../../../../services/server.js"; import toastService from "../../../../services/toast.js"; import { t } from "../../../../services/i18n.js"; import options from "../../../../services/options.js"; -import { OpenAIModelResponse, AnthropicModelResponse, OllamaModelResponse } from "./interfaces.js"; +import type { OpenAIModelResponse, AnthropicModelResponse, OllamaModelResponse } from "./interfaces.js"; export class ProviderService { constructor(private $widget: JQuery) { // Initialize Voyage models (since they don't have a dynamic refresh yet) this.initializeVoyageModels(); } - + /** * Initialize Voyage models with default values and ensure proper selection */ @@ -22,7 +22,7 @@ export class ProviderService { } }, 100); // Small delay to ensure the widget is fully initialized } - + /** * Ensures the dropdown has the correct value set, prioritizing: * 1. Current UI value if present @@ -57,14 +57,14 @@ export class ProviderService { */ async refreshOpenAIModels(showLoading: boolean, openaiModelsRefreshed: boolean): Promise { if (!this.$widget) return false; - + const $refreshOpenAIModels = this.$widget.find('.refresh-openai-models'); - + // If we've already refreshed and we're not forcing a refresh, don't do it again if (openaiModelsRefreshed && !showLoading) { return openaiModelsRefreshed; } - + if (showLoading) { $refreshOpenAIModels.prop('disabled', true); $refreshOpenAIModels.html(``); @@ -72,7 +72,7 @@ export class ProviderService { try { const openaiBaseUrl = this.$widget.find('.openai-base-url').val() as string; - const response = await server.post('openai/list-models', { baseUrl: openaiBaseUrl }); + const response = await server.get(`llm/providers/openai/models?baseUrl=${encodeURIComponent(openaiBaseUrl)}`); if (response && response.success) { // Update the chat models dropdown @@ -120,12 +120,12 @@ export class ProviderService { const totalModels = (response.chatModels?.length || 0) + (response.embeddingModels?.length || 0); toastService.showMessage(`${totalModels} OpenAI models found.`); } - + return true; } else if (showLoading) { toastService.showError(`No OpenAI models found. Please check your API key and settings.`); } - + return openaiModelsRefreshed; } catch (e) { console.error(`Error fetching OpenAI models:`, e); @@ -140,7 +140,7 @@ export class ProviderService { } } } - + /** * Refreshes the list of Anthropic models * @param showLoading Whether to show loading indicators and toasts @@ -149,14 +149,14 @@ export class ProviderService { */ async refreshAnthropicModels(showLoading: boolean, anthropicModelsRefreshed: boolean): Promise { if (!this.$widget) return false; - + const $refreshAnthropicModels = this.$widget.find('.refresh-anthropic-models'); - + // If we've already refreshed and we're not forcing a refresh, don't do it again if (anthropicModelsRefreshed && !showLoading) { return anthropicModelsRefreshed; } - + if (showLoading) { $refreshAnthropicModels.prop('disabled', true); $refreshAnthropicModels.html(``); @@ -164,7 +164,7 @@ export class ProviderService { try { const anthropicBaseUrl = this.$widget.find('.anthropic-base-url').val() as string; - const response = await server.post('anthropic/list-models', { baseUrl: anthropicBaseUrl }); + const response = await server.get(`llm/providers/anthropic/models?baseUrl=${encodeURIComponent(anthropicBaseUrl)}`); if (response && response.success) { // Update the chat models dropdown @@ -197,12 +197,12 @@ export class ProviderService { const totalModels = (response.chatModels?.length || 0) + (response.embeddingModels?.length || 0); toastService.showMessage(`${totalModels} Anthropic models found.`); } - + return true; } else if (showLoading) { toastService.showError(`No Anthropic models found. Please check your API key and settings.`); } - + return anthropicModelsRefreshed; } catch (e) { console.error(`Error fetching Anthropic models:`, e); @@ -217,7 +217,7 @@ export class ProviderService { } } } - + /** * Refreshes the list of Ollama models * @param showLoading Whether to show loading indicators and toasts @@ -226,14 +226,14 @@ export class ProviderService { */ async refreshOllamaModels(showLoading: boolean, ollamaModelsRefreshed: boolean): Promise { if (!this.$widget) return false; - + const $refreshModels = this.$widget.find('.refresh-models'); - + // If we've already refreshed and we're not forcing a refresh, don't do it again if (ollamaModelsRefreshed && !showLoading) { return ollamaModelsRefreshed; } - + if (showLoading) { $refreshModels.prop('disabled', true); $refreshModels.text(t("ai_llm.refreshing_models")); @@ -241,7 +241,7 @@ export class ProviderService { try { const ollamaBaseUrl = this.$widget.find('.ollama-base-url').val() as string; - const response = await server.post('ollama/list-models', { baseUrl: ollamaBaseUrl }); + const response = await server.get(`llm/providers/ollama/models?baseUrl=${encodeURIComponent(ollamaBaseUrl)}`); if (response && response.success && response.models && response.models.length > 0) { const $embedModelSelect = this.$widget.find('.ollama-embedding-model'); @@ -295,12 +295,12 @@ export class ProviderService { if (showLoading) { toastService.showMessage(`${response.models.length} Ollama models found.`); } - + return true; } else if (showLoading) { toastService.showError(`No Ollama models found. Please check if Ollama is running.`); } - + return ollamaModelsRefreshed; } catch (e) { console.error(`Error fetching Ollama models:`, e); @@ -315,4 +315,4 @@ export class ProviderService { } } } -} \ No newline at end of file +} diff --git a/src/routes/api/llm.ts b/src/routes/api/llm.ts index 7d4672128..24138aeb4 100644 --- a/src/routes/api/llm.ts +++ b/src/routes/api/llm.ts @@ -1144,39 +1144,34 @@ async function sendMessage(req: Request, res: Response) { /** * @swagger - * /api/llm/index/stats: + * /api/llm/indexes/stats: * get: - * summary: Get statistics about the vector index + * summary: Get stats about the LLM knowledge base indexing status * operationId: llm-index-stats * responses: * '200': - * description: Vector index statistics - * content: - * application/json: - * schema: - * type: object - * properties: - * totalEmbeddings: - * type: integer - * totalIndexedNotes: - * type: integer - * lastIndexed: - * type: string - * format: date-time - * embeddingProvider: - * type: string + * description: Index stats successfully retrieved * security: * - session: [] * tags: ["llm"] */ async function getIndexStats(req: Request, res: Response) { try { - if (!isDatabaseInitialized()) { - throw new Error('Database is not initialized yet'); + // Check if AI is enabled + const aiEnabled = await options.getOptionBool('aiEnabled'); + if (!aiEnabled) { + return { + success: false, + message: "AI features are disabled" + }; } + // Return indexing stats const stats = await indexService.getIndexingStats(); - return stats; + return { + success: true, + ...stats + }; } catch (error: any) { log.error(`Error getting index stats: ${error.message || 'Unknown error'}`); throw new Error(`Failed to get index stats: ${error.message || 'Unknown error'}`); @@ -1185,9 +1180,9 @@ async function getIndexStats(req: Request, res: Response) { /** * @swagger - * /api/llm/index/start: + * /api/llm/indexes: * post: - * summary: Start or restart the indexing process + * summary: Start or continue indexing the knowledge base * operationId: llm-start-indexing * requestBody: * required: false @@ -1196,413 +1191,345 @@ async function getIndexStats(req: Request, res: Response) { * schema: * type: object * properties: - * forceReindex: - * type: boolean - * description: Whether to force reindexing of all notes - * branchId: - * type: string - * description: Optional branch ID to limit indexing scope - * responses: - * '200': - * description: Indexing process started - * content: - * application/json: - * schema: - * type: object - * properties: - * message: - * type: string - * notesToIndex: - * type: integer - * security: - * - session: [] - * tags: ["llm"] - */ -async function startIndexing(req: Request, res: Response) { - try { - if (!isDatabaseInitialized()) { - throw new Error('Database is not initialized yet'); - } - - const { force, batchSize } = req.body || {}; - - let result; - if (batchSize) { - // Run a limited batch indexing - result = await indexService.runBatchIndexing(batchSize); - return { - success: result, - message: result ? `Batch indexing started with size ${batchSize}` : 'Indexing already in progress' - }; - } else { - // Start full indexing - result = await indexService.startFullIndexing(force); - return { - success: result, - message: result ? 'Full indexing started' : 'Indexing already in progress or not needed' - }; - } - } catch (error: any) { - log.error(`Error starting indexing: ${error.message || 'Unknown error'}`); - throw new Error(`Failed to start indexing: ${error.message || 'Unknown error'}`); - } -} - -/** - * @swagger - * /api/llm/index/failed: - * get: - * summary: Get list of notes that failed to be indexed - * operationId: llm-failed-indexes - * responses: - * '200': - * description: List of failed note indexes - * content: - * application/json: - * schema: - * type: array - * items: - * type: object - * properties: - * noteId: - * type: string - * title: - * type: string - * error: - * type: string - * timestamp: - * type: string - * format: date-time - * security: - * - session: [] - * tags: ["llm"] - */ -async function getFailedIndexes(req: Request, res: Response) { - try { - if (!isDatabaseInitialized()) { - throw new Error('Database is not initialized yet'); - } - - const limit = req.query.limit ? parseInt(req.query.limit as string, 10) : 100; - const failedNotes = await indexService.getFailedIndexes(limit); - - return { - count: failedNotes.length, - failedNotes - }; - } catch (error: any) { - log.error(`Error getting failed indexes: ${error.message || 'Unknown error'}`); - throw new Error(`Failed to get failed indexes: ${error.message || 'Unknown error'}`); - } -} - -/** - * @swagger - * /api/llm/index/failed/{noteId}/retry: - * post: - * summary: Retry indexing a specific failed note - * operationId: llm-retry-failed-index - * parameters: - * - name: noteId - * in: path - * required: true - * schema: - * type: string - * responses: - * '200': - * description: Retry process started - * content: - * application/json: - * schema: - * type: object - * properties: - * success: - * type: boolean - * message: - * type: string - * '404': - * description: Failed note not found - * security: - * - session: [] - * tags: ["llm"] - */ -async function retryFailedIndex(req: Request, res: Response) { - try { - if (!isDatabaseInitialized()) { - throw new Error('Database is not initialized yet'); - } - - const { noteId } = req.params; - if (!noteId) { - throw new Error('Note ID is required'); - } - - const success = await indexService.retryFailedNote(noteId); - - return { - success, - message: success ? `Note ${noteId} queued for retry` : `Note ${noteId} not found in failed queue` - }; - } catch (error: any) { - log.error(`Error retrying failed index: ${error.message || 'Unknown error'}`); - throw new Error(`Failed to retry index: ${error.message || 'Unknown error'}`); - } -} - -/** - * @swagger - * /api/llm/index/failed/retry-all: - * post: - * summary: Retry indexing all failed notes - * operationId: llm-retry-all-failed - * responses: - * '200': - * description: Retry process started for all failed notes - * content: - * application/json: - * schema: - * type: object - * properties: - * success: - * type: boolean - * message: - * type: string - * count: - * type: integer - * security: - * - session: [] - * tags: ["llm"] - */ -async function retryAllFailedIndexes(req: Request, res: Response) { - try { - if (!isDatabaseInitialized()) { - throw new Error('Database is not initialized yet'); - } - - const count = await indexService.retryAllFailedNotes(); - - return { - success: true, - count, - message: `${count} notes queued for retry` - }; - } catch (error: any) { - log.error(`Error retrying all failed indexes: ${error.message || 'Unknown error'}`); - throw new Error(`Failed to retry indexes: ${error.message || 'Unknown error'}`); - } -} - -/** - * @swagger - * /api/llm/similar: - * post: - * summary: Find notes similar to the provided content - * operationId: llm-find-similar - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * content: - * type: string - * description: Content to find similar notes for - * limit: - * type: integer - * description: Maximum number of results to return - * threshold: - * type: number - * description: Similarity threshold (0.0-1.0) - * responses: - * '200': - * description: List of similar notes - * content: - * application/json: - * schema: - * type: array - * items: - * type: object - * properties: - * noteId: - * type: string - * title: - * type: string - * similarity: - * type: number - * branchId: - * type: string - * security: - * - session: [] - * tags: ["llm"] - */ -async function findSimilarNotes(req: Request, res: Response) { - try { - if (!isDatabaseInitialized()) { - throw new Error('Database is not initialized yet'); - } - - const { query, contextNoteId, limit } = req.body || {}; - - if (!query || typeof query !== 'string' || query.trim().length === 0) { - throw new Error('Query is required'); - } - - const similarNotes = await indexService.findSimilarNotes( - query, - contextNoteId, - limit || 10 - ); - - return { - count: similarNotes.length, - similarNotes - }; - } catch (error: any) { - log.error(`Error finding similar notes: ${error.message || 'Unknown error'}`); - throw new Error(`Failed to find similar notes: ${error.message || 'Unknown error'}`); - } -} - -/** - * @swagger - * /api/llm/generate-context: - * post: - * summary: Generate context from similar notes for a query - * operationId: llm-generate-context - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * query: - * type: string - * description: Query to generate context for - * limit: - * type: integer - * description: Maximum number of notes to include - * contextNoteId: - * type: string - * description: Optional note ID to provide additional context - * responses: - * '200': - * description: Generated context and sources - * content: - * application/json: - * schema: - * type: object - * properties: - * context: - * type: string - * sources: - * type: array - * items: - * type: object - * properties: - * noteId: - * type: string - * title: - * type: string - * similarity: - * type: number - * security: - * - session: [] - * tags: ["llm"] - */ -async function generateQueryContext(req: Request, res: Response) { - try { - if (!isDatabaseInitialized()) { - throw new Error('Database is not initialized yet'); - } - - const { query, contextNoteId, depth } = req.body || {}; - - if (!query || typeof query !== 'string' || query.trim().length === 0) { - throw new Error('Query is required'); - } - - const context = await indexService.generateQueryContext( - query, - contextNoteId, - depth || 2 - ); - - return { - context, - length: context.length - }; - } catch (error: any) { - log.error(`Error generating query context: ${error.message || 'Unknown error'}`); - throw new Error(`Failed to generate query context: ${error.message || 'Unknown error'}`); - } -} - -/** - * @swagger - * /api/llm/index/note/{noteId}: - * post: - * summary: Index or reindex a specific note - * operationId: llm-index-note - * parameters: - * - name: noteId - * in: path - * required: true - * schema: - * type: string - * requestBody: - * required: false - * content: - * application/json: - * schema: - * type: object - * properties: * force: * type: boolean - * description: Whether to force reindexing even if already indexed + * description: Whether to force reindexing of all notes * responses: * '200': - * description: Note indexing result - * content: - * application/json: - * schema: - * type: object - * properties: - * success: - * type: boolean - * message: - * type: string - * '404': - * description: Note not found + * description: Indexing started successfully + * security: + * - session: [] + * tags: ["llm"] + */ +async function startIndexing(req: Request, res: Response) { + try { + // Check if AI is enabled + const aiEnabled = await options.getOptionBool('aiEnabled'); + if (!aiEnabled) { + return { + success: false, + message: "AI features are disabled" + }; + } + + const { force = false } = req.body; + + // Start indexing + await indexService.startFullIndexing(force); + + return { + success: true, + message: "Indexing started" + }; + } catch (error: any) { + log.error(`Error starting indexing: ${error.message || 'Unknown error'}`); + throw new Error(`Failed to start indexing: ${error.message || 'Unknown error'}`); + } +} + +/** + * @swagger + * /api/llm/indexes/failed: + * get: + * summary: Get list of notes that failed to index + * operationId: llm-failed-indexes + * parameters: + * - name: limit + * in: query + * required: false + * schema: + * type: integer + * default: 100 + * responses: + * '200': + * description: Failed indexes successfully retrieved + * security: + * - session: [] + * tags: ["llm"] + */ +async function getFailedIndexes(req: Request, res: Response) { + try { + // Check if AI is enabled + const aiEnabled = await options.getOptionBool('aiEnabled'); + if (!aiEnabled) { + return { + success: false, + message: "AI features are disabled" + }; + } + + const limit = parseInt(req.query.limit as string || "100", 10); + + // Get failed indexes + const failed = await indexService.getFailedIndexes(limit); + + return { + success: true, + failed + }; + } catch (error: any) { + log.error(`Error getting failed indexes: ${error.message || 'Unknown error'}`); + throw new Error(`Failed to get failed indexes: ${error.message || 'Unknown error'}`); + } +} + +/** + * @swagger + * /api/llm/indexes/notes/{noteId}: + * put: + * summary: Retry indexing a specific note that previously failed + * operationId: llm-retry-index + * parameters: + * - name: noteId + * in: path + * required: true + * schema: + * type: string + * responses: + * '200': + * description: Index retry successfully initiated + * security: + * - session: [] + * tags: ["llm"] + */ +async function retryFailedIndex(req: Request, res: Response) { + try { + // Check if AI is enabled + const aiEnabled = await options.getOptionBool('aiEnabled'); + if (!aiEnabled) { + return { + success: false, + message: "AI features are disabled" + }; + } + + const { noteId } = req.params; + + // Retry indexing the note + const result = await indexService.retryFailedNote(noteId); + + return { + success: true, + message: result ? "Note queued for indexing" : "Failed to queue note for indexing" + }; + } catch (error: any) { + log.error(`Error retrying failed index: ${error.message || 'Unknown error'}`); + throw new Error(`Failed to retry index: ${error.message || 'Unknown error'}`); + } +} + +/** + * @swagger + * /api/llm/indexes/failed: + * put: + * summary: Retry indexing all failed notes + * operationId: llm-retry-all-indexes + * responses: + * '200': + * description: Retry of all failed indexes successfully initiated + * security: + * - session: [] + * tags: ["llm"] + */ +async function retryAllFailedIndexes(req: Request, res: Response) { + try { + // Check if AI is enabled + const aiEnabled = await options.getOptionBool('aiEnabled'); + if (!aiEnabled) { + return { + success: false, + message: "AI features are disabled" + }; + } + + // Retry all failed notes + const count = await indexService.retryAllFailedNotes(); + + return { + success: true, + message: `${count} notes queued for reprocessing` + }; + } catch (error: any) { + log.error(`Error retrying all failed indexes: ${error.message || 'Unknown error'}`); + throw new Error(`Failed to retry all indexes: ${error.message || 'Unknown error'}`); + } +} + +/** + * @swagger + * /api/llm/indexes/notes/similar: + * get: + * summary: Find notes similar to a query string + * operationId: llm-find-similar-notes + * parameters: + * - name: query + * in: query + * required: true + * schema: + * type: string + * - name: contextNoteId + * in: query + * required: false + * schema: + * type: string + * - name: limit + * in: query + * required: false + * schema: + * type: integer + * default: 5 + * responses: + * '200': + * description: Similar notes found successfully + * security: + * - session: [] + * tags: ["llm"] + */ +async function findSimilarNotes(req: Request, res: Response) { + try { + // Check if AI is enabled + const aiEnabled = await options.getOptionBool('aiEnabled'); + if (!aiEnabled) { + return { + success: false, + message: "AI features are disabled" + }; + } + + const query = req.query.query as string; + const contextNoteId = req.query.contextNoteId as string | undefined; + const limit = parseInt(req.query.limit as string || "5", 10); + + if (!query) { + return { + success: false, + message: "Query is required" + }; + } + + // Find similar notes + const similar = await indexService.findSimilarNotes(query, contextNoteId, limit); + + return { + success: true, + similar + }; + } catch (error: any) { + log.error(`Error finding similar notes: ${error.message || 'Unknown error'}`); + throw new Error(`Failed to find similar notes: ${error.message || 'Unknown error'}`); + } +} + +/** + * @swagger + * /api/llm/indexes/context: + * get: + * summary: Generate context for an LLM query based on the knowledge base + * operationId: llm-generate-context + * parameters: + * - name: query + * in: query + * required: true + * schema: + * type: string + * - name: contextNoteId + * in: query + * required: false + * schema: + * type: string + * - name: depth + * in: query + * required: false + * schema: + * type: integer + * default: 2 + * responses: + * '200': + * description: Context generated successfully + * security: + * - session: [] + * tags: ["llm"] + */ +async function generateQueryContext(req: Request, res: Response) { + try { + // Check if AI is enabled + const aiEnabled = await options.getOptionBool('aiEnabled'); + if (!aiEnabled) { + return { + success: false, + message: "AI features are disabled" + }; + } + + const query = req.query.query as string; + const contextNoteId = req.query.contextNoteId as string | undefined; + const depth = parseInt(req.query.depth as string || "2", 10); + + if (!query) { + return { + success: false, + message: "Query is required" + }; + } + + // Generate context + const context = await indexService.generateQueryContext(query, contextNoteId, depth); + + return { + success: true, + context + }; + } catch (error: any) { + log.error(`Error generating query context: ${error.message || 'Unknown error'}`); + throw new Error(`Failed to generate query context: ${error.message || 'Unknown error'}`); + } +} + +/** + * @swagger + * /api/llm/indexes/notes/{noteId}: + * post: + * summary: Index a specific note for LLM knowledge base + * operationId: llm-index-note + * parameters: + * - name: noteId + * in: path + * required: true + * schema: + * type: string + * responses: + * '200': + * description: Note indexed successfully * security: * - session: [] * tags: ["llm"] */ async function indexNote(req: Request, res: Response) { try { - if (!isDatabaseInitialized()) { - throw new Error('Database is not initialized yet'); + // Check if AI is enabled + const aiEnabled = await options.getOptionBool('aiEnabled'); + if (!aiEnabled) { + return { + success: false, + message: "AI features are disabled" + }; } const { noteId } = req.params; + if (!noteId) { - throw new Error('Note ID is required'); + return { + success: false, + message: "Note ID is required" + }; } - // Check if note exists - const note = becca.getNote(noteId); - if (!note) { - throw new Error(`Note ${noteId} not found`); - } - - const success = await indexService.generateNoteIndex(noteId); + // Index the note + const result = await indexService.generateNoteIndex(noteId); return { - success, - noteId, - noteTitle: note.title, - message: success ? `Note "${note.title}" indexed successfully` : `Failed to index note "${note.title}"` + success: true, + message: result ? "Note indexed successfully" : "Failed to index note" }; } catch (error: any) { log.error(`Error indexing note: ${error.message || 'Unknown error'}`); diff --git a/src/routes/api/ollama.ts b/src/routes/api/ollama.ts index a0f42afb8..4f368a882 100644 --- a/src/routes/api/ollama.ts +++ b/src/routes/api/ollama.ts @@ -5,20 +5,17 @@ import type { Request, Response } from "express"; /** * @swagger - * /api/ollama/models: - * post: + * /api/llm/providers/ollama/models: + * get: * summary: List available models from Ollama * operationId: ollama-list-models - * requestBody: - * required: false - * content: - * application/json: - * schema: - * type: object - * properties: - * baseUrl: - * type: string - * description: Optional custom Ollama API base URL + * parameters: + * - name: baseUrl + * in: query + * required: false + * schema: + * type: string + * description: Optional custom Ollama API base URL * responses: * '200': * description: List of available Ollama models @@ -41,13 +38,10 @@ import type { Request, Response } from "express"; */ async function listModels(req: Request, res: Response) { try { - const { baseUrl } = req.body; - - // Use provided base URL or default from options - const ollamaBaseUrl = baseUrl || await options.getOption('ollamaBaseUrl') || 'http://localhost:11434'; + const baseUrl = req.query.baseUrl as string || await options.getOption('ollamaBaseUrl') || 'http://localhost:11434'; // Call Ollama API to get models - const response = await axios.get(`${ollamaBaseUrl}/api/tags?format=json`, { + const response = await axios.get(`${baseUrl}/api/tags?format=json`, { headers: { 'Content-Type': 'application/json' }, timeout: 10000 }); diff --git a/src/routes/routes.ts b/src/routes/routes.ts index d0705bd51..0b3ef9ff5 100644 --- a/src/routes/routes.ts +++ b/src/routes/routes.ts @@ -414,24 +414,20 @@ function register(app: express.Application) { apiRoute(PST, "/api/llm/sessions/:sessionId/messages", llmRoute.sendMessage); apiRoute(GET, "/api/llm/sessions/:sessionId/messages", llmRoute.sendMessage); - // LLM index management endpoints - apiRoute(GET, "/api/llm/index/stats", llmRoute.getIndexStats); - apiRoute(PST, "/api/llm/index/start", llmRoute.startIndexing); - apiRoute(GET, "/api/llm/index/failed", llmRoute.getFailedIndexes); - apiRoute(PST, "/api/llm/index/retry/:noteId", llmRoute.retryFailedIndex); - apiRoute(PST, "/api/llm/index/retry-all", llmRoute.retryAllFailedIndexes); - apiRoute(PST, "/api/llm/index/similar", llmRoute.findSimilarNotes); - apiRoute(PST, "/api/llm/index/context", llmRoute.generateQueryContext); - apiRoute(PST, "/api/llm/index/notes/:noteId", llmRoute.indexNote); + // LLM index management endpoints - reorganized for REST principles + apiRoute(GET, "/api/llm/indexes/stats", llmRoute.getIndexStats); + apiRoute(PST, "/api/llm/indexes", llmRoute.startIndexing); // Create index process + apiRoute(GET, "/api/llm/indexes/failed", llmRoute.getFailedIndexes); + apiRoute(PUT, "/api/llm/indexes/notes/:noteId", llmRoute.retryFailedIndex); // Update index for note + apiRoute(PUT, "/api/llm/indexes/failed", llmRoute.retryAllFailedIndexes); // Update all failed indexes + apiRoute(GET, "/api/llm/indexes/notes/similar", llmRoute.findSimilarNotes); // Get similar notes + apiRoute(GET, "/api/llm/indexes/context", llmRoute.generateQueryContext); // Get context + apiRoute(PST, "/api/llm/indexes/notes/:noteId", llmRoute.indexNote); // Create index for specific note - // Ollama API endpoints - apiRoute(PST, "/api/ollama/list-models", ollamaRoute.listModels); - - // OpenAI API endpoints - apiRoute(PST, "/api/openai/list-models", openaiRoute.listModels); - - // Anthropic API endpoints - apiRoute(PST, "/api/anthropic/list-models", anthropicRoute.listModels); + // LLM provider endpoints - moved under /api/llm/providers hierarchy + apiRoute(GET, "/api/llm/providers/ollama/models", ollamaRoute.listModels); + apiRoute(GET, "/api/llm/providers/openai/models", openaiRoute.listModels); + apiRoute(GET, "/api/llm/providers/anthropic/models", anthropicRoute.listModels); // API Documentation apiDocsRoute.register(app);