Skip to content

Commit df6a80b

Browse files
authored
feat: Add a model refresh button to manually refresh on-disk yaml (#6150)
Add a model refresh button
1 parent 21faa41 commit df6a80b

File tree

3 files changed

+108
-1
lines changed

3 files changed

+108
-1
lines changed

core/http/endpoints/localai/edit_model.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,33 @@ func EditModelEndpoint(cl *config.ModelConfigLoader, appConfig *config.Applicati
226226
return c.JSON(response)
227227
}
228228
}
229+
230+
// ReloadModelsEndpoint handles reloading model configurations from disk
231+
func ReloadModelsEndpoint(cl *config.ModelConfigLoader, appConfig *config.ApplicationConfig) fiber.Handler {
232+
return func(c *fiber.Ctx) error {
233+
// Reload configurations
234+
if err := cl.LoadModelConfigsFromPath(appConfig.SystemState.Model.ModelsPath); err != nil {
235+
response := ModelResponse{
236+
Success: false,
237+
Error: "Failed to reload configurations: " + err.Error(),
238+
}
239+
return c.Status(500).JSON(response)
240+
}
241+
242+
// Preload the models
243+
if err := cl.Preload(appConfig.SystemState.Model.ModelsPath); err != nil {
244+
response := ModelResponse{
245+
Success: false,
246+
Error: "Failed to preload models: " + err.Error(),
247+
}
248+
return c.Status(500).JSON(response)
249+
}
250+
251+
// Return success response
252+
response := ModelResponse{
253+
Success: true,
254+
Message: "Model configurations reloaded successfully",
255+
}
256+
return c.Status(fiber.StatusOK).JSON(response)
257+
}
258+
}

core/http/routes/localai.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ func RegisterLocalAIRoutes(router *fiber.App,
5959

6060
// Custom model edit endpoint
6161
router.Post("/models/edit/:name", localai.EditModelEndpoint(cl, appConfig))
62+
63+
// Reload models endpoint
64+
router.Post("/models/reload", localai.ReloadModelsEndpoint(cl, appConfig))
6265
}
6366

6467
router.Post("/v1/detection",

core/http/views/index.html

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,21 @@ <h1 class="text-5xl md:text-6xl font-bold text-white mb-6">
4141
<div class="absolute inset-0 rounded-xl bg-white/10 opacity-0 group-hover:opacity-100 transition-opacity"></div>
4242
</a>
4343

44-
<a href="/import-model"
44+
<a href="/import-model"
4545
class="group relative inline-flex items-center bg-gradient-to-r from-green-600 to-emerald-600 hover:from-green-700 hover:to-emerald-700 text-white py-3 px-8 rounded-xl font-semibold transition-all duration-300 ease-in-out transform hover:scale-105 hover:shadow-xl hover:shadow-green-500/25">
4646
<i class="fas fa-plus mr-3 text-lg"></i>
4747
<span>Import Model</span>
4848
<i class="fas fa-upload ml-3 opacity-70 group-hover:opacity-100 transition-opacity"></i>
4949
<div class="absolute inset-0 rounded-xl bg-white/10 opacity-0 group-hover:opacity-100 transition-opacity"></div>
5050
</a>
51+
52+
<button id="reload-models-btn"
53+
class="group relative inline-flex items-center bg-gradient-to-r from-orange-600 to-amber-600 hover:from-orange-700 hover:to-amber-700 text-white py-3 px-8 rounded-xl font-semibold transition-all duration-300 ease-in-out transform hover:scale-105 hover:shadow-xl hover:shadow-orange-500/25">
54+
<i class="fas fa-sync-alt mr-3 text-lg"></i>
55+
<span>Update Models</span>
56+
<i class="fas fa-refresh ml-3 opacity-70 group-hover:opacity-100 transition-opacity"></i>
57+
<div class="absolute inset-0 rounded-xl bg-white/10 opacity-0 group-hover:opacity-100 transition-opacity"></div>
58+
</button>
5159
</div>
5260
</div>
5361
</div>
@@ -319,6 +327,72 @@ <h3 class="font-bold text-xl text-white truncate mb-2">{{.Name}}</h3>
319327
const response = event.detail.xhr;
320328
window.location.reload();
321329
}
330+
331+
// Handle reload models button
332+
document.addEventListener('DOMContentLoaded', function() {
333+
const reloadBtn = document.getElementById('reload-models-btn');
334+
if (reloadBtn) {
335+
reloadBtn.addEventListener('click', function() {
336+
const button = this;
337+
const originalText = button.querySelector('span').textContent;
338+
const icon = button.querySelector('i');
339+
340+
// Show loading state
341+
button.disabled = true;
342+
button.querySelector('span').textContent = 'Updating...';
343+
icon.classList.add('fa-spin');
344+
345+
// Make the API call
346+
fetch('/models/reload', {
347+
method: 'POST',
348+
headers: {
349+
'Content-Type': 'application/json',
350+
}
351+
})
352+
.then(response => response.json())
353+
.then(data => {
354+
if (data.success) {
355+
// Show success state briefly
356+
button.querySelector('span').textContent = 'Updated!';
357+
icon.classList.remove('fa-spin', 'fa-sync-alt');
358+
icon.classList.add('fa-check');
359+
360+
// Reload the page after a short delay
361+
setTimeout(() => {
362+
window.location.reload();
363+
}, 1000);
364+
} else {
365+
// Show error state
366+
button.querySelector('span').textContent = 'Error!';
367+
icon.classList.remove('fa-spin');
368+
console.error('Failed to reload models:', data.error);
369+
370+
// Reset button after delay
371+
setTimeout(() => {
372+
button.disabled = false;
373+
button.querySelector('span').textContent = originalText;
374+
icon.classList.remove('fa-check');
375+
icon.classList.add('fa-sync-alt');
376+
}, 3000);
377+
}
378+
})
379+
.catch(error => {
380+
// Show error state
381+
button.querySelector('span').textContent = 'Error!';
382+
icon.classList.remove('fa-spin');
383+
console.error('Error reloading models:', error);
384+
385+
// Reset button after delay
386+
setTimeout(() => {
387+
button.disabled = false;
388+
button.querySelector('span').textContent = originalText;
389+
icon.classList.remove('fa-check');
390+
icon.classList.add('fa-sync-alt');
391+
}, 3000);
392+
});
393+
});
394+
}
395+
});
322396
</script>
323397

324398
</body>

0 commit comments

Comments
 (0)