Spaces:
Configuration error
Configuration error
package gallery | |
import ( | |
"errors" | |
"fmt" | |
"os" | |
"path/filepath" | |
"dario.cat/mergo" | |
lconfig "github.com/mudler/LocalAI/core/config" | |
"github.com/mudler/LocalAI/pkg/downloader" | |
"github.com/mudler/LocalAI/pkg/utils" | |
"github.com/rs/zerolog/log" | |
"gopkg.in/yaml.v2" | |
) | |
/* | |
description: | | |
foo | |
license: "" | |
urls: | |
- | |
- | |
name: "bar" | |
config_file: | | |
# Note, name will be injected. or generated by the alias wanted by the user | |
threads: 14 | |
files: | |
- filename: "" | |
sha: "" | |
uri: "" | |
prompt_templates: | |
- name: "" | |
content: "" | |
*/ | |
// Config is the model configuration which contains all the model details | |
// This configuration is read from the gallery endpoint and is used to download and install the model | |
// It is the internal structure, separated from the request | |
type Config struct { | |
Description string `yaml:"description"` | |
Icon string `yaml:"icon"` | |
License string `yaml:"license"` | |
URLs []string `yaml:"urls"` | |
Name string `yaml:"name"` | |
ConfigFile string `yaml:"config_file"` | |
Files []File `yaml:"files"` | |
PromptTemplates []PromptTemplate `yaml:"prompt_templates"` | |
} | |
type File struct { | |
Filename string `yaml:"filename" json:"filename"` | |
SHA256 string `yaml:"sha256" json:"sha256"` | |
URI string `yaml:"uri" json:"uri"` | |
} | |
type PromptTemplate struct { | |
Name string `yaml:"name"` | |
Content string `yaml:"content"` | |
} | |
func GetGalleryConfigFromURL(url string, basePath string) (Config, error) { | |
var config Config | |
uri := downloader.URI(url) | |
err := uri.DownloadWithCallback(basePath, func(url string, d []byte) error { | |
return yaml.Unmarshal(d, &config) | |
}) | |
if err != nil { | |
log.Error().Err(err).Str("url", url).Msg("failed to get gallery config for url") | |
return config, err | |
} | |
return config, nil | |
} | |
func ReadConfigFile(filePath string) (*Config, error) { | |
// Read the YAML file | |
yamlFile, err := os.ReadFile(filePath) | |
if err != nil { | |
return nil, fmt.Errorf("failed to read YAML file: %v", err) | |
} | |
// Unmarshal YAML data into a Config struct | |
var config Config | |
err = yaml.Unmarshal(yamlFile, &config) | |
if err != nil { | |
return nil, fmt.Errorf("failed to unmarshal YAML: %v", err) | |
} | |
return &config, nil | |
} | |
func InstallModel(basePath, nameOverride string, config *Config, configOverrides map[string]interface{}, downloadStatus func(string, string, string, float64), enforceScan bool) error { | |
// Create base path if it doesn't exist | |
err := os.MkdirAll(basePath, 0750) | |
if err != nil { | |
return fmt.Errorf("failed to create base path: %v", err) | |
} | |
if len(configOverrides) > 0 { | |
log.Debug().Msgf("Config overrides %+v", configOverrides) | |
} | |
// Download files and verify their SHA | |
for i, file := range config.Files { | |
log.Debug().Msgf("Checking %q exists and matches SHA", file.Filename) | |
if err := utils.VerifyPath(file.Filename, basePath); err != nil { | |
return err | |
} | |
// Create file path | |
filePath := filepath.Join(basePath, file.Filename) | |
if enforceScan { | |
scanResults, err := downloader.HuggingFaceScan(downloader.URI(file.URI)) | |
if err != nil && errors.Is(err, downloader.ErrUnsafeFilesFound) { | |
log.Error().Str("model", config.Name).Strs("clamAV", scanResults.ClamAVInfectedFiles).Strs("pickles", scanResults.DangerousPickles).Msg("Contains unsafe file(s)!") | |
return err | |
} | |
} | |
uri := downloader.URI(file.URI) | |
if err := uri.DownloadFile(filePath, file.SHA256, i, len(config.Files), downloadStatus); err != nil { | |
return err | |
} | |
} | |
// Write prompt template contents to separate files | |
for _, template := range config.PromptTemplates { | |
if err := utils.VerifyPath(template.Name+".tmpl", basePath); err != nil { | |
return err | |
} | |
// Create file path | |
filePath := filepath.Join(basePath, template.Name+".tmpl") | |
// Create parent directory | |
err := os.MkdirAll(filepath.Dir(filePath), 0750) | |
if err != nil { | |
return fmt.Errorf("failed to create parent directory for prompt template %q: %v", template.Name, err) | |
} | |
// Create and write file content | |
err = os.WriteFile(filePath, []byte(template.Content), 0600) | |
if err != nil { | |
return fmt.Errorf("failed to write prompt template %q: %v", template.Name, err) | |
} | |
log.Debug().Msgf("Prompt template %q written", template.Name) | |
} | |
name := config.Name | |
if nameOverride != "" { | |
name = nameOverride | |
} | |
if err := utils.VerifyPath(name+".yaml", basePath); err != nil { | |
return err | |
} | |
// write config file | |
if len(configOverrides) != 0 || len(config.ConfigFile) != 0 { | |
configFilePath := filepath.Join(basePath, name+".yaml") | |
// Read and update config file as map[string]interface{} | |
configMap := make(map[string]interface{}) | |
err = yaml.Unmarshal([]byte(config.ConfigFile), &configMap) | |
if err != nil { | |
return fmt.Errorf("failed to unmarshal config YAML: %v", err) | |
} | |
configMap["name"] = name | |
if err := mergo.Merge(&configMap, configOverrides, mergo.WithOverride); err != nil { | |
return err | |
} | |
// Write updated config file | |
updatedConfigYAML, err := yaml.Marshal(configMap) | |
if err != nil { | |
return fmt.Errorf("failed to marshal updated config YAML: %v", err) | |
} | |
backendConfig := lconfig.BackendConfig{} | |
err = yaml.Unmarshal(updatedConfigYAML, &backendConfig) | |
if err != nil { | |
return fmt.Errorf("failed to unmarshal updated config YAML: %v", err) | |
} | |
if !backendConfig.Validate() { | |
return fmt.Errorf("failed to validate updated config YAML") | |
} | |
err = os.WriteFile(configFilePath, updatedConfigYAML, 0600) | |
if err != nil { | |
return fmt.Errorf("failed to write updated config file: %v", err) | |
} | |
log.Debug().Msgf("Written config file %s", configFilePath) | |
} | |
// Save the model gallery file for further reference | |
modelFile := filepath.Join(basePath, galleryFileName(name)) | |
data, err := yaml.Marshal(config) | |
if err != nil { | |
return err | |
} | |
log.Debug().Msgf("Written gallery file %s", modelFile) | |
return os.WriteFile(modelFile, data, 0600) | |
//return nil | |
} | |
func galleryFileName(name string) string { | |
return "._gallery_" + name + ".yaml" | |
} | |