From 2423014989e571fc5706919998615a30eb2bdf5b Mon Sep 17 00:00:00 2001 From: Matt Cowger Date: Tue, 26 Aug 2025 11:32:38 -0700 Subject: [PATCH] Add a model refresh button --- core/http/endpoints/localai/edit_model.go | 30 +++++++++ core/http/routes/localai.go | 3 + core/http/views/index.html | 76 ++++++++++++++++++++++- 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/core/http/endpoints/localai/edit_model.go b/core/http/endpoints/localai/edit_model.go index 91961509841c..de93632cebdd 100644 --- a/core/http/endpoints/localai/edit_model.go +++ b/core/http/endpoints/localai/edit_model.go @@ -226,3 +226,33 @@ func EditModelEndpoint(cl *config.ModelConfigLoader, appConfig *config.Applicati return c.JSON(response) } } + +// ReloadModelsEndpoint handles reloading model configurations from disk +func ReloadModelsEndpoint(cl *config.ModelConfigLoader, appConfig *config.ApplicationConfig) fiber.Handler { + return func(c *fiber.Ctx) error { + // Reload configurations + if err := cl.LoadModelConfigsFromPath(appConfig.SystemState.Model.ModelsPath); err != nil { + response := ModelResponse{ + Success: false, + Error: "Failed to reload configurations: " + err.Error(), + } + return c.Status(500).JSON(response) + } + + // Preload the models + if err := cl.Preload(appConfig.SystemState.Model.ModelsPath); err != nil { + response := ModelResponse{ + Success: false, + Error: "Failed to preload models: " + err.Error(), + } + return c.Status(500).JSON(response) + } + + // Return success response + response := ModelResponse{ + Success: true, + Message: "Model configurations reloaded successfully", + } + return c.Status(fiber.StatusOK).JSON(response) + } +} diff --git a/core/http/routes/localai.go b/core/http/routes/localai.go index 9a7c1d868153..298f5fd787b3 100644 --- a/core/http/routes/localai.go +++ b/core/http/routes/localai.go @@ -59,6 +59,9 @@ func RegisterLocalAIRoutes(router *fiber.App, // Custom model edit endpoint router.Post("/models/edit/:name", localai.EditModelEndpoint(cl, appConfig)) + + // Reload models endpoint + router.Post("/models/reload", localai.ReloadModelsEndpoint(cl, appConfig)) } router.Post("/v1/detection", diff --git a/core/http/views/index.html b/core/http/views/index.html index fcafdfcd4b03..4c429f7b6975 100644 --- a/core/http/views/index.html +++ b/core/http/views/index.html @@ -41,13 +41,21 @@

- Import Model
+ + @@ -319,6 +327,72 @@

{{.Name}}

const response = event.detail.xhr; window.location.reload(); } + +// Handle reload models button +document.addEventListener('DOMContentLoaded', function() { + const reloadBtn = document.getElementById('reload-models-btn'); + if (reloadBtn) { + reloadBtn.addEventListener('click', function() { + const button = this; + const originalText = button.querySelector('span').textContent; + const icon = button.querySelector('i'); + + // Show loading state + button.disabled = true; + button.querySelector('span').textContent = 'Updating...'; + icon.classList.add('fa-spin'); + + // Make the API call + fetch('/models/reload', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + } + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + // Show success state briefly + button.querySelector('span').textContent = 'Updated!'; + icon.classList.remove('fa-spin', 'fa-sync-alt'); + icon.classList.add('fa-check'); + + // Reload the page after a short delay + setTimeout(() => { + window.location.reload(); + }, 1000); + } else { + // Show error state + button.querySelector('span').textContent = 'Error!'; + icon.classList.remove('fa-spin'); + console.error('Failed to reload models:', data.error); + + // Reset button after delay + setTimeout(() => { + button.disabled = false; + button.querySelector('span').textContent = originalText; + icon.classList.remove('fa-check'); + icon.classList.add('fa-sync-alt'); + }, 3000); + } + }) + .catch(error => { + // Show error state + button.querySelector('span').textContent = 'Error!'; + icon.classList.remove('fa-spin'); + console.error('Error reloading models:', error); + + // Reset button after delay + setTimeout(() => { + button.disabled = false; + button.querySelector('span').textContent = originalText; + icon.classList.remove('fa-check'); + icon.classList.add('fa-sync-alt'); + }, 3000); + }); + }); + } +});