| | package localai |
| |
|
| | import ( |
| | "encoding/json" |
| | "io" |
| | "net/http" |
| | "os" |
| | "path/filepath" |
| | "time" |
| |
|
| | "github.com/labstack/echo/v4" |
| | "github.com/mudler/LocalAI/core/application" |
| | "github.com/mudler/LocalAI/core/config" |
| | "github.com/mudler/LocalAI/core/p2p" |
| | "github.com/mudler/LocalAI/core/schema" |
| | "github.com/mudler/xlog" |
| | ) |
| |
|
| | |
| | func GetSettingsEndpoint(app *application.Application) echo.HandlerFunc { |
| | return func(c echo.Context) error { |
| | appConfig := app.ApplicationConfig() |
| | settings := appConfig.ToRuntimeSettings() |
| | return c.JSON(http.StatusOK, settings) |
| | } |
| | } |
| |
|
| | |
| | func UpdateSettingsEndpoint(app *application.Application) echo.HandlerFunc { |
| | return func(c echo.Context) error { |
| | appConfig := app.ApplicationConfig() |
| | startupConfig := app.StartupConfig() |
| |
|
| | if startupConfig == nil { |
| | startupConfig = appConfig |
| | } |
| |
|
| | body, err := io.ReadAll(c.Request().Body) |
| | if err != nil { |
| | return c.JSON(http.StatusBadRequest, schema.SettingsResponse{ |
| | Success: false, |
| | Error: "Failed to read request body: " + err.Error(), |
| | }) |
| | } |
| |
|
| | var settings config.RuntimeSettings |
| | if err := json.Unmarshal(body, &settings); err != nil { |
| | return c.JSON(http.StatusBadRequest, schema.SettingsResponse{ |
| | Success: false, |
| | Error: "Failed to parse JSON: " + err.Error(), |
| | }) |
| | } |
| |
|
| | |
| | if settings.WatchdogIdleTimeout != nil { |
| | if _, err := time.ParseDuration(*settings.WatchdogIdleTimeout); err != nil { |
| | return c.JSON(http.StatusBadRequest, schema.SettingsResponse{ |
| | Success: false, |
| | Error: "Invalid watchdog_idle_timeout format: " + err.Error(), |
| | }) |
| | } |
| | } |
| | if settings.WatchdogBusyTimeout != nil { |
| | if _, err := time.ParseDuration(*settings.WatchdogBusyTimeout); err != nil { |
| | return c.JSON(http.StatusBadRequest, schema.SettingsResponse{ |
| | Success: false, |
| | Error: "Invalid watchdog_busy_timeout format: " + err.Error(), |
| | }) |
| | } |
| | } |
| | if settings.WatchdogInterval != nil { |
| | if _, err := time.ParseDuration(*settings.WatchdogInterval); err != nil { |
| | return c.JSON(http.StatusBadRequest, schema.SettingsResponse{ |
| | Success: false, |
| | Error: "Invalid watchdog_interval format: " + err.Error(), |
| | }) |
| | } |
| | } |
| | if settings.LRUEvictionRetryInterval != nil { |
| | if _, err := time.ParseDuration(*settings.LRUEvictionRetryInterval); err != nil { |
| | return c.JSON(http.StatusBadRequest, schema.SettingsResponse{ |
| | Success: false, |
| | Error: "Invalid lru_eviction_retry_interval format: " + err.Error(), |
| | }) |
| | } |
| | } |
| |
|
| | |
| | if appConfig.DynamicConfigsDir == "" { |
| | return c.JSON(http.StatusBadRequest, schema.SettingsResponse{ |
| | Success: false, |
| | Error: "DynamicConfigsDir is not set", |
| | }) |
| | } |
| |
|
| | settingsFile := filepath.Join(appConfig.DynamicConfigsDir, "runtime_settings.json") |
| | settingsJSON, err := json.MarshalIndent(settings, "", " ") |
| | if err != nil { |
| | return c.JSON(http.StatusInternalServerError, schema.SettingsResponse{ |
| | Success: false, |
| | Error: "Failed to marshal settings: " + err.Error(), |
| | }) |
| | } |
| |
|
| | if err := os.WriteFile(settingsFile, settingsJSON, 0600); err != nil { |
| | return c.JSON(http.StatusInternalServerError, schema.SettingsResponse{ |
| | Success: false, |
| | Error: "Failed to write settings file: " + err.Error(), |
| | }) |
| | } |
| |
|
| | |
| | watchdogChanged := appConfig.ApplyRuntimeSettings(&settings) |
| |
|
| | |
| | if settings.ApiKeys != nil { |
| | envKeys := startupConfig.ApiKeys |
| | runtimeKeys := *settings.ApiKeys |
| | appConfig.ApiKeys = append(envKeys, runtimeKeys...) |
| | } |
| |
|
| | |
| | if settings.ForceEvictionWhenBusy != nil { |
| | currentWD := app.ModelLoader().GetWatchDog() |
| | if currentWD != nil { |
| | currentWD.SetForceEvictionWhenBusy(*settings.ForceEvictionWhenBusy) |
| | xlog.Info("Updated watchdog force eviction when busy setting", "forceEvictionWhenBusy", *settings.ForceEvictionWhenBusy) |
| | } |
| | } |
| |
|
| | |
| | maxRetries := appConfig.LRUEvictionMaxRetries |
| | retryInterval := appConfig.LRUEvictionRetryInterval |
| | if settings.LRUEvictionMaxRetries != nil { |
| | maxRetries = *settings.LRUEvictionMaxRetries |
| | } |
| | if settings.LRUEvictionRetryInterval != nil { |
| | if dur, err := time.ParseDuration(*settings.LRUEvictionRetryInterval); err == nil { |
| | retryInterval = dur |
| | } |
| | } |
| | if settings.LRUEvictionMaxRetries != nil || settings.LRUEvictionRetryInterval != nil { |
| | app.ModelLoader().SetLRUEvictionRetrySettings(maxRetries, retryInterval) |
| | xlog.Info("Updated LRU eviction retry settings", "maxRetries", maxRetries, "retryInterval", retryInterval) |
| | } |
| |
|
| | |
| | agentJobChanged := settings.AgentJobRetentionDays != nil |
| |
|
| | |
| | if watchdogChanged { |
| | if settings.WatchdogEnabled != nil && !*settings.WatchdogEnabled { |
| | if err := app.StopWatchdog(); err != nil { |
| | xlog.Error("Failed to stop watchdog", "error", err) |
| | return c.JSON(http.StatusInternalServerError, schema.SettingsResponse{ |
| | Success: false, |
| | Error: "Settings saved but failed to stop watchdog: " + err.Error(), |
| | }) |
| | } |
| | } else { |
| | if err := app.RestartWatchdog(); err != nil { |
| | xlog.Error("Failed to restart watchdog", "error", err) |
| | return c.JSON(http.StatusInternalServerError, schema.SettingsResponse{ |
| | Success: false, |
| | Error: "Settings saved but failed to restart watchdog: " + err.Error(), |
| | }) |
| | } |
| | } |
| | } |
| |
|
| | |
| | if agentJobChanged { |
| | if err := app.RestartAgentJobService(); err != nil { |
| | xlog.Error("Failed to restart agent job service", "error", err) |
| | return c.JSON(http.StatusInternalServerError, schema.SettingsResponse{ |
| | Success: false, |
| | Error: "Settings saved but failed to restart agent job service: " + err.Error(), |
| | }) |
| | } |
| | } |
| |
|
| | |
| | p2pChanged := settings.P2PToken != nil || settings.P2PNetworkID != nil || settings.Federated != nil |
| | if p2pChanged { |
| | if settings.P2PToken != nil && *settings.P2PToken == "" { |
| | if err := app.StopP2P(); err != nil { |
| | xlog.Error("Failed to stop P2P", "error", err) |
| | return c.JSON(http.StatusInternalServerError, schema.SettingsResponse{ |
| | Success: false, |
| | Error: "Settings saved but failed to stop P2P: " + err.Error(), |
| | }) |
| | } |
| | } else { |
| | if settings.P2PToken != nil && *settings.P2PToken == "0" { |
| | token := p2p.GenerateToken(60, 60) |
| | settings.P2PToken = &token |
| | appConfig.P2PToken = token |
| | } |
| | if err := app.RestartP2P(); err != nil { |
| | xlog.Error("Failed to restart P2P", "error", err) |
| | return c.JSON(http.StatusInternalServerError, schema.SettingsResponse{ |
| | Success: false, |
| | Error: "Settings saved but failed to restart P2P: " + err.Error(), |
| | }) |
| | } |
| | } |
| | } |
| |
|
| | return c.JSON(http.StatusOK, schema.SettingsResponse{ |
| | Success: true, |
| | Message: "Settings updated successfully", |
| | }) |
| | } |
| | } |
| |
|