Spaces:
Configuration error
Configuration error
| package services | |
| import ( | |
| "context" | |
| "encoding/json" | |
| "fmt" | |
| "os" | |
| "path/filepath" | |
| "sync" | |
| "github.com/mudler/LocalAI/core/config" | |
| "github.com/mudler/LocalAI/core/gallery" | |
| "github.com/mudler/LocalAI/pkg/startup" | |
| "github.com/mudler/LocalAI/pkg/utils" | |
| "gopkg.in/yaml.v2" | |
| ) | |
| type GalleryService struct { | |
| appConfig *config.ApplicationConfig | |
| sync.Mutex | |
| C chan gallery.GalleryOp | |
| statuses map[string]*gallery.GalleryOpStatus | |
| } | |
| func NewGalleryService(appConfig *config.ApplicationConfig) *GalleryService { | |
| return &GalleryService{ | |
| appConfig: appConfig, | |
| C: make(chan gallery.GalleryOp), | |
| statuses: make(map[string]*gallery.GalleryOpStatus), | |
| } | |
| } | |
| func prepareModel(modelPath string, req gallery.GalleryModel, downloadStatus func(string, string, string, float64), enforceScan bool) error { | |
| config, err := gallery.GetGalleryConfigFromURL(req.URL, modelPath) | |
| if err != nil { | |
| return err | |
| } | |
| config.Files = append(config.Files, req.AdditionalFiles...) | |
| return gallery.InstallModel(modelPath, req.Name, &config, req.Overrides, downloadStatus, enforceScan) | |
| } | |
| func (g *GalleryService) UpdateStatus(s string, op *gallery.GalleryOpStatus) { | |
| g.Lock() | |
| defer g.Unlock() | |
| g.statuses[s] = op | |
| } | |
| func (g *GalleryService) GetStatus(s string) *gallery.GalleryOpStatus { | |
| g.Lock() | |
| defer g.Unlock() | |
| return g.statuses[s] | |
| } | |
| func (g *GalleryService) GetAllStatus() map[string]*gallery.GalleryOpStatus { | |
| g.Lock() | |
| defer g.Unlock() | |
| return g.statuses | |
| } | |
| func (g *GalleryService) Start(c context.Context, cl *config.BackendConfigLoader) { | |
| go func() { | |
| for { | |
| select { | |
| case <-c.Done(): | |
| return | |
| case op := <-g.C: | |
| utils.ResetDownloadTimers() | |
| g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Message: "processing", Progress: 0}) | |
| // updates the status with an error | |
| var updateError func(e error) | |
| if !g.appConfig.OpaqueErrors { | |
| updateError = func(e error) { | |
| g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Error: e, Processed: true, Message: "error: " + e.Error()}) | |
| } | |
| } else { | |
| updateError = func(_ error) { | |
| g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Error: fmt.Errorf("an error occurred"), Processed: true}) | |
| } | |
| } | |
| // displayDownload displays the download progress | |
| progressCallback := func(fileName string, current string, total string, percentage float64) { | |
| g.UpdateStatus(op.Id, &gallery.GalleryOpStatus{Message: "processing", FileName: fileName, Progress: percentage, TotalFileSize: total, DownloadedFileSize: current}) | |
| utils.DisplayDownloadFunction(fileName, current, total, percentage) | |
| } | |
| var err error | |
| // delete a model | |
| if op.Delete { | |
| modelConfig := &config.BackendConfig{} | |
| // Galleryname is the name of the model in this case | |
| dat, err := os.ReadFile(filepath.Join(g.appConfig.ModelPath, op.GalleryModelName+".yaml")) | |
| if err != nil { | |
| updateError(err) | |
| continue | |
| } | |
| err = yaml.Unmarshal(dat, modelConfig) | |
| if err != nil { | |
| updateError(err) | |
| continue | |
| } | |
| files := []string{} | |
| // Remove the model from the config | |
| if modelConfig.Model != "" { | |
| files = append(files, modelConfig.ModelFileName()) | |
| } | |
| if modelConfig.MMProj != "" { | |
| files = append(files, modelConfig.MMProjFileName()) | |
| } | |
| err = gallery.DeleteModelFromSystem(g.appConfig.ModelPath, op.GalleryModelName, files) | |
| if err != nil { | |
| updateError(err) | |
| continue | |
| } | |
| } else { | |
| // if the request contains a gallery name, we apply the gallery from the gallery list | |
| if op.GalleryModelName != "" { | |
| err = gallery.InstallModelFromGallery(op.Galleries, op.GalleryModelName, g.appConfig.ModelPath, op.Req, progressCallback, g.appConfig.EnforcePredownloadScans) | |
| } else if op.ConfigURL != "" { | |
| err = startup.InstallModels(op.Galleries, op.ConfigURL, g.appConfig.ModelPath, g.appConfig.EnforcePredownloadScans, progressCallback, op.ConfigURL) | |
| if err != nil { | |
| updateError(err) | |
| continue | |
| } | |
| err = cl.Preload(g.appConfig.ModelPath) | |
| } else { | |
| err = prepareModel(g.appConfig.ModelPath, op.Req, progressCallback, g.appConfig.EnforcePredownloadScans) | |
| } | |
| } | |
| if err != nil { | |
| updateError(err) | |
| continue | |
| } | |
| // Reload models | |
| err = cl.LoadBackendConfigsFromPath(g.appConfig.ModelPath) | |
| if err != nil { | |
| updateError(err) | |
| continue | |
| } | |
| err = cl.Preload(g.appConfig.ModelPath) | |
| if err != nil { | |
| updateError(err) | |
| continue | |
| } | |
| g.UpdateStatus(op.Id, | |
| &gallery.GalleryOpStatus{ | |
| Deletion: op.Delete, | |
| Processed: true, | |
| GalleryModelName: op.GalleryModelName, | |
| Message: "completed", | |
| Progress: 100}) | |
| } | |
| } | |
| }() | |
| } | |
| type galleryModel struct { | |
| gallery.GalleryModel `yaml:",inline"` // https://github.com/go-yaml/yaml/issues/63 | |
| ID string `json:"id"` | |
| } | |
| func processRequests(modelPath string, enforceScan bool, galleries []config.Gallery, requests []galleryModel) error { | |
| var err error | |
| for _, r := range requests { | |
| utils.ResetDownloadTimers() | |
| if r.ID == "" { | |
| err = prepareModel(modelPath, r.GalleryModel, utils.DisplayDownloadFunction, enforceScan) | |
| } else { | |
| err = gallery.InstallModelFromGallery( | |
| galleries, r.ID, modelPath, r.GalleryModel, utils.DisplayDownloadFunction, enforceScan) | |
| } | |
| } | |
| return err | |
| } | |
| func ApplyGalleryFromFile(modelPath, s string, enforceScan bool, galleries []config.Gallery) error { | |
| dat, err := os.ReadFile(s) | |
| if err != nil { | |
| return err | |
| } | |
| var requests []galleryModel | |
| if err := yaml.Unmarshal(dat, &requests); err != nil { | |
| return err | |
| } | |
| return processRequests(modelPath, enforceScan, galleries, requests) | |
| } | |
| func ApplyGalleryFromString(modelPath, s string, enforceScan bool, galleries []config.Gallery) error { | |
| var requests []galleryModel | |
| err := json.Unmarshal([]byte(s), &requests) | |
| if err != nil { | |
| return err | |
| } | |
| return processRequests(modelPath, enforceScan, galleries, requests) | |
| } | |