diff --git a/core/config/model_config.go b/core/config/model_config.go index e372febb7239..1cfe0f411371 100644 --- a/core/config/model_config.go +++ b/core/config/model_config.go @@ -26,6 +26,7 @@ type TTSConfig struct { // ModelConfig represents a model configuration type ModelConfig struct { + modelConfigFile string `yaml:"-" json:"-"` schema.PredictionOptions `yaml:"parameters" json:"parameters"` Name string `yaml:"name" json:"name"` @@ -492,6 +493,10 @@ func (c *ModelConfig) HasTemplate() bool { return c.TemplateConfig.Completion != "" || c.TemplateConfig.Edit != "" || c.TemplateConfig.Chat != "" || c.TemplateConfig.ChatMessage != "" } +func (c *ModelConfig) GetModelConfigFile() string { + return c.modelConfigFile +} + type ModelConfigUsecases int const ( diff --git a/core/config/model_config_loader.go b/core/config/model_config_loader.go index 5b16cadc8758..9895a4a0e5f8 100644 --- a/core/config/model_config_loader.go +++ b/core/config/model_config_loader.go @@ -88,6 +88,7 @@ func readMultipleModelConfigsFromFile(file string, opts ...ConfigLoaderOption) ( } for _, cc := range *c { + cc.modelConfigFile = file cc.SetDefaults(opts...) } @@ -108,6 +109,8 @@ func readModelConfigFromFile(file string, opts ...ConfigLoaderOption) (*ModelCon } c.SetDefaults(opts...) + + c.modelConfigFile = file return c, nil } diff --git a/core/http/endpoints/localai/edit_model.go b/core/http/endpoints/localai/edit_model.go index de93632cebdd..d68775e1f5f5 100644 --- a/core/http/endpoints/localai/edit_model.go +++ b/core/http/endpoints/localai/edit_model.go @@ -1,11 +1,8 @@ package localai import ( - "encoding/json" "fmt" "os" - "path/filepath" - "strings" "github.com/gofiber/fiber/v2" "github.com/mudler/LocalAI/core/config" @@ -37,21 +34,19 @@ func GetEditModelPage(cl *config.ModelConfigLoader, appConfig *config.Applicatio return c.Status(404).JSON(response) } - configData, err := yaml.Marshal(modelConfig) - if err != nil { + modelConfigFile := modelConfig.GetModelConfigFile() + if modelConfigFile == "" { response := ModelResponse{ Success: false, - Error: "Failed to marshal configuration: " + err.Error(), + Error: "Model configuration file not found", } - return c.Status(500).JSON(response) + return c.Status(404).JSON(response) } - - // Marshal the config to JSON for the template - configJSON, err := json.Marshal(modelConfig) + configData, err := os.ReadFile(modelConfigFile) if err != nil { response := ModelResponse{ Success: false, - Error: "Failed to marshal configuration: " + err.Error(), + Error: "Failed to read configuration file: " + err.Error(), } return c.Status(500).JSON(response) } @@ -69,7 +64,6 @@ func GetEditModelPage(cl *config.ModelConfigLoader, appConfig *config.Applicatio Title: "LocalAI - Edit Model " + modelName, ModelName: modelName, Config: &modelConfig, - ConfigJSON: string(configJSON), ConfigYAML: string(configData), BaseURL: httpUtils.BaseURL(c), Version: internal.PrintableVersion(), @@ -91,6 +85,15 @@ func EditModelEndpoint(cl *config.ModelConfigLoader, appConfig *config.Applicati return c.Status(400).JSON(response) } + modelConfig, exists := cl.GetModelConfig(modelName) + if !exists { + response := ModelResponse{ + Success: false, + Error: "Existing model configuration not found", + } + return c.Status(404).JSON(response) + } + // Get the raw body body := c.Body() if len(body) == 0 { @@ -101,50 +104,16 @@ func EditModelEndpoint(cl *config.ModelConfigLoader, appConfig *config.Applicati return c.Status(400).JSON(response) } - // Check content type to determine how to parse - contentType := string(c.Context().Request.Header.ContentType()) + // Check content to see if it's a valid model config var req config.ModelConfig - var err error - if strings.Contains(contentType, "application/json") { - // Parse JSON - if err := json.Unmarshal(body, &req); err != nil { - response := ModelResponse{ - Success: false, - Error: "Failed to parse JSON: " + err.Error(), - } - return c.Status(400).JSON(response) - } - } else if strings.Contains(contentType, "application/x-yaml") || strings.Contains(contentType, "text/yaml") { - // Parse YAML - if err := yaml.Unmarshal(body, &req); err != nil { - response := ModelResponse{ - Success: false, - Error: "Failed to parse YAML: " + err.Error(), - } - return c.Status(400).JSON(response) - } - } else { - // Try to auto-detect format - if strings.TrimSpace(string(body))[0] == '{' { - // Looks like JSON - if err := json.Unmarshal(body, &req); err != nil { - response := ModelResponse{ - Success: false, - Error: "Failed to parse JSON: " + err.Error(), - } - return c.Status(400).JSON(response) - } - } else { - // Assume YAML - if err := yaml.Unmarshal(body, &req); err != nil { - response := ModelResponse{ - Success: false, - Error: "Failed to parse YAML: " + err.Error(), - } - return c.Status(400).JSON(response) - } + // Parse YAML + if err := yaml.Unmarshal(body, &req); err != nil { + response := ModelResponse{ + Success: false, + Error: "Failed to parse YAML: " + err.Error(), } + return c.Status(400).JSON(response) } // Validate required fields @@ -156,19 +125,6 @@ func EditModelEndpoint(cl *config.ModelConfigLoader, appConfig *config.Applicati return c.Status(400).JSON(response) } - // Load the existing configuration - configPath := filepath.Join(appConfig.SystemState.Model.ModelsPath, modelName+".yaml") - if err := utils.VerifyPath(modelName+".yaml", appConfig.SystemState.Model.ModelsPath); err != nil { - response := ModelResponse{ - Success: false, - Error: "Model configuration not trusted: " + err.Error(), - } - return c.Status(404).JSON(response) - } - - // Set defaults - req.SetDefaults() - // Validate the configuration if !req.Validate() { response := ModelResponse{ @@ -179,18 +135,18 @@ func EditModelEndpoint(cl *config.ModelConfigLoader, appConfig *config.Applicati return c.Status(400).JSON(response) } - // Create the YAML file - yamlData, err := yaml.Marshal(req) - if err != nil { + // Load the existing configuration + configPath := modelConfig.GetModelConfigFile() + if err := utils.VerifyPath(configPath, appConfig.SystemState.Model.ModelsPath); err != nil { response := ModelResponse{ Success: false, - Error: "Failed to marshal configuration: " + err.Error(), + Error: "Model configuration not trusted: " + err.Error(), } - return c.Status(500).JSON(response) + return c.Status(404).JSON(response) } - // Write to file - if err := os.WriteFile(configPath, yamlData, 0644); err != nil { + // Write new content to file + if err := os.WriteFile(configPath, body, 0644); err != nil { response := ModelResponse{ Success: false, Error: "Failed to write configuration file: " + err.Error(), diff --git a/core/http/views/model-editor.html b/core/http/views/model-editor.html index 440ca8c7a56a..d5cbc550b7c4 100644 --- a/core/http/views/model-editor.html +++ b/core/http/views/model-editor.html @@ -24,7 +24,7 @@
Configure your model settings using the form or YAML editor
+Configure your model settings using YAML