ImportModelEndpoint handles creating new model configurations
(cl *config.ModelConfigLoader, gs *galleryop.GalleryService, appConfig *config.ApplicationConfig)
| 126 | |
| 127 | // ImportModelEndpoint handles creating new model configurations |
| 128 | func ImportModelEndpoint(cl *config.ModelConfigLoader, gs *galleryop.GalleryService, appConfig *config.ApplicationConfig) echo.HandlerFunc { |
| 129 | return func(c echo.Context) error { |
| 130 | // Get the raw body |
| 131 | body, err := io.ReadAll(c.Request().Body) |
| 132 | if err != nil { |
| 133 | response := ModelResponse{ |
| 134 | Success: false, |
| 135 | Error: "Failed to read request body: " + err.Error(), |
| 136 | } |
| 137 | return c.JSON(http.StatusBadRequest, response) |
| 138 | } |
| 139 | if len(body) == 0 { |
| 140 | response := ModelResponse{ |
| 141 | Success: false, |
| 142 | Error: "Request body is empty", |
| 143 | } |
| 144 | return c.JSON(http.StatusBadRequest, response) |
| 145 | } |
| 146 | |
| 147 | // Detect format once and reuse for both typed and map parsing |
| 148 | contentType := c.Request().Header.Get("Content-Type") |
| 149 | trimmed := strings.TrimSpace(string(body)) |
| 150 | isJSON := strings.Contains(contentType, "application/json") || |
| 151 | (!strings.Contains(contentType, "yaml") && len(trimmed) > 0 && trimmed[0] == '{') |
| 152 | |
| 153 | var modelConfig config.ModelConfig |
| 154 | if isJSON { |
| 155 | if err := json.Unmarshal(body, &modelConfig); err != nil { |
| 156 | return c.JSON(http.StatusBadRequest, ModelResponse{Success: false, Error: "Failed to parse JSON: " + err.Error()}) |
| 157 | } |
| 158 | } else { |
| 159 | if err := yaml.Unmarshal(body, &modelConfig); err != nil { |
| 160 | return c.JSON(http.StatusBadRequest, ModelResponse{Success: false, Error: "Failed to parse YAML: " + err.Error()}) |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | // Validate required fields |
| 165 | if modelConfig.Name == "" { |
| 166 | response := ModelResponse{ |
| 167 | Success: false, |
| 168 | Error: "Name is required", |
| 169 | } |
| 170 | return c.JSON(http.StatusBadRequest, response) |
| 171 | } |
| 172 | |
| 173 | // Validate without calling SetDefaults() — runtime defaults should not |
| 174 | // be persisted to disk. SetDefaults() is called when loading configs |
| 175 | // for inference via LoadModelConfigsFromPath(). |
| 176 | if valid, vErr := modelConfig.Validate(); !valid { |
| 177 | msg := "Invalid configuration" |
| 178 | if vErr != nil { |
| 179 | msg = vErr.Error() |
| 180 | } |
| 181 | return c.JSON(http.StatusBadRequest, ModelResponse{Success: false, Error: msg}) |
| 182 | } |
| 183 | |
| 184 | // Reject aliases whose target is missing, chained, or disabled so a |
| 185 | // dangling alias can't be persisted and surface as a runtime error later. |
no test coverage detected