mirror of
https://github.com/mudler/LocalAI.git
synced 2026-04-17 05:18:53 -04:00
- UpgradeChecker background service: checks every 6h, auto-upgrades when enabled - API endpoints: GET /backends/upgrades, POST /backends/upgrades/check, POST /backends/upgrade/:name - CLI: `localai backends upgrade` command, version display in `backends list` - BackendManager interface: add UpgradeBackend and CheckUpgrades methods - Wire upgrade op through GalleryService backend handler - Distributed mode: fan-out upgrade to worker nodes via NATS
231 lines
6.9 KiB
Go
231 lines
6.9 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
cliContext "github.com/mudler/LocalAI/core/cli/context"
|
|
"github.com/mudler/LocalAI/core/config"
|
|
"github.com/mudler/LocalAI/core/gallery"
|
|
"github.com/mudler/LocalAI/core/services/galleryop"
|
|
"github.com/mudler/LocalAI/pkg/model"
|
|
"github.com/mudler/LocalAI/pkg/system"
|
|
|
|
"github.com/mudler/xlog"
|
|
"github.com/schollz/progressbar/v3"
|
|
)
|
|
|
|
type BackendsCMDFlags struct {
|
|
BackendGalleries string `env:"LOCALAI_BACKEND_GALLERIES,BACKEND_GALLERIES" help:"JSON list of backend galleries" group:"backends" default:"${backends}"`
|
|
BackendsPath string `env:"LOCALAI_BACKENDS_PATH,BACKENDS_PATH" type:"path" default:"${basepath}/backends" help:"Path containing backends used for inferencing" group:"storage"`
|
|
BackendsSystemPath string `env:"LOCALAI_BACKENDS_SYSTEM_PATH,BACKEND_SYSTEM_PATH" type:"path" default:"/var/lib/local-ai/backends" help:"Path containing system backends used for inferencing" group:"backends"`
|
|
}
|
|
|
|
type BackendsList struct {
|
|
BackendsCMDFlags `embed:""`
|
|
}
|
|
|
|
type BackendsInstall struct {
|
|
BackendArgs string `arg:"" optional:"" name:"backend" help:"Backend configuration URL to load"`
|
|
Name string `arg:"" optional:"" name:"name" help:"Name of the backend"`
|
|
Alias string `arg:"" optional:"" name:"alias" help:"Alias of the backend"`
|
|
|
|
BackendsCMDFlags `embed:""`
|
|
}
|
|
|
|
type BackendsUninstall struct {
|
|
BackendArgs []string `arg:"" name:"backends" help:"Backend names to uninstall"`
|
|
|
|
BackendsCMDFlags `embed:""`
|
|
}
|
|
|
|
type BackendsUpgrade struct {
|
|
BackendArgs []string `arg:"" optional:"" name:"backends" help:"Backend names to upgrade (empty = upgrade all)"`
|
|
|
|
BackendsCMDFlags `embed:""`
|
|
}
|
|
|
|
type BackendsCMD struct {
|
|
List BackendsList `cmd:"" help:"List the backends available in your galleries" default:"withargs"`
|
|
Install BackendsInstall `cmd:"" help:"Install a backend from the gallery"`
|
|
Uninstall BackendsUninstall `cmd:"" help:"Uninstall a backend"`
|
|
Upgrade BackendsUpgrade `cmd:"" help:"Upgrade backends to latest versions"`
|
|
}
|
|
|
|
func (bl *BackendsList) Run(ctx *cliContext.Context) error {
|
|
var galleries []config.Gallery
|
|
if err := json.Unmarshal([]byte(bl.BackendGalleries), &galleries); err != nil {
|
|
xlog.Error("unable to load galleries", "error", err)
|
|
}
|
|
|
|
systemState, err := system.GetSystemState(
|
|
system.WithBackendSystemPath(bl.BackendsSystemPath),
|
|
system.WithBackendPath(bl.BackendsPath),
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
backends, err := gallery.AvailableBackends(galleries, systemState)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Check for upgrades
|
|
upgrades, _ := gallery.CheckBackendUpgrades(context.Background(), galleries, systemState)
|
|
|
|
for _, backend := range backends {
|
|
versionStr := ""
|
|
if backend.Version != "" {
|
|
versionStr = " v" + backend.Version
|
|
}
|
|
if backend.Installed {
|
|
if info, ok := upgrades[backend.Name]; ok {
|
|
upgradeStr := info.AvailableVersion
|
|
if upgradeStr == "" {
|
|
upgradeStr = "new build"
|
|
}
|
|
fmt.Printf(" * %s@%s%s (installed, upgrade available: %s)\n", backend.Gallery.Name, backend.Name, versionStr, upgradeStr)
|
|
} else {
|
|
fmt.Printf(" * %s@%s%s (installed)\n", backend.Gallery.Name, backend.Name, versionStr)
|
|
}
|
|
} else {
|
|
fmt.Printf(" - %s@%s%s\n", backend.Gallery.Name, backend.Name, versionStr)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (bi *BackendsInstall) Run(ctx *cliContext.Context) error {
|
|
var galleries []config.Gallery
|
|
if err := json.Unmarshal([]byte(bi.BackendGalleries), &galleries); err != nil {
|
|
xlog.Error("unable to load galleries", "error", err)
|
|
}
|
|
|
|
systemState, err := system.GetSystemState(
|
|
system.WithBackendSystemPath(bi.BackendsSystemPath),
|
|
system.WithBackendPath(bi.BackendsPath),
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
progressBar := progressbar.NewOptions(
|
|
1000,
|
|
progressbar.OptionSetDescription(fmt.Sprintf("downloading backend %s", bi.BackendArgs)),
|
|
progressbar.OptionShowBytes(false),
|
|
progressbar.OptionClearOnFinish(),
|
|
)
|
|
progressCallback := func(fileName string, current string, total string, percentage float64) {
|
|
v := int(percentage * 10)
|
|
err := progressBar.Set(v)
|
|
if err != nil {
|
|
xlog.Error("error while updating progress bar", "error", err, "filename", fileName, "value", v)
|
|
}
|
|
}
|
|
|
|
modelLoader := model.NewModelLoader(systemState)
|
|
err = galleryop.InstallExternalBackend(context.Background(), galleries, systemState, modelLoader, progressCallback, bi.BackendArgs, bi.Name, bi.Alias)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (bu *BackendsUpgrade) Run(ctx *cliContext.Context) error {
|
|
var galleries []config.Gallery
|
|
if err := json.Unmarshal([]byte(bu.BackendGalleries), &galleries); err != nil {
|
|
xlog.Error("unable to load galleries", "error", err)
|
|
}
|
|
|
|
systemState, err := system.GetSystemState(
|
|
system.WithBackendSystemPath(bu.BackendsSystemPath),
|
|
system.WithBackendPath(bu.BackendsPath),
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
upgrades, err := gallery.CheckBackendUpgrades(context.Background(), galleries, systemState)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to check for upgrades: %w", err)
|
|
}
|
|
|
|
if len(upgrades) == 0 {
|
|
fmt.Println("All backends are up to date.")
|
|
return nil
|
|
}
|
|
|
|
// Filter to specified backends if args given
|
|
toUpgrade := upgrades
|
|
if len(bu.BackendArgs) > 0 {
|
|
toUpgrade = make(map[string]gallery.UpgradeInfo)
|
|
for _, name := range bu.BackendArgs {
|
|
if info, ok := upgrades[name]; ok {
|
|
toUpgrade[name] = info
|
|
} else {
|
|
fmt.Printf("Backend %s: no upgrade available\n", name)
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(toUpgrade) == 0 {
|
|
fmt.Println("No upgrades to apply.")
|
|
return nil
|
|
}
|
|
|
|
modelLoader := model.NewModelLoader(systemState)
|
|
for name, info := range toUpgrade {
|
|
versionStr := ""
|
|
if info.AvailableVersion != "" {
|
|
versionStr = " to v" + info.AvailableVersion
|
|
}
|
|
fmt.Printf("Upgrading %s%s...\n", name, versionStr)
|
|
|
|
progressBar := progressbar.NewOptions(
|
|
1000,
|
|
progressbar.OptionSetDescription(fmt.Sprintf("downloading %s", name)),
|
|
progressbar.OptionShowBytes(false),
|
|
progressbar.OptionClearOnFinish(),
|
|
)
|
|
progressCallback := func(fileName string, current string, total string, percentage float64) {
|
|
v := int(percentage * 10)
|
|
if err := progressBar.Set(v); err != nil {
|
|
xlog.Error("error updating progress bar", "error", err)
|
|
}
|
|
}
|
|
|
|
if err := gallery.UpgradeBackend(context.Background(), systemState, modelLoader, galleries, name, progressCallback); err != nil {
|
|
fmt.Printf("Failed to upgrade %s: %v\n", name, err)
|
|
} else {
|
|
fmt.Printf("Backend %s upgraded successfully\n", name)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (bu *BackendsUninstall) Run(ctx *cliContext.Context) error {
|
|
for _, backendName := range bu.BackendArgs {
|
|
xlog.Info("uninstalling backend", "backend", backendName)
|
|
|
|
systemState, err := system.GetSystemState(
|
|
system.WithBackendSystemPath(bu.BackendsSystemPath),
|
|
system.WithBackendPath(bu.BackendsPath),
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = gallery.DeleteBackendFromSystem(systemState, backendName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("Backend %s uninstalled successfully\n", backendName)
|
|
}
|
|
return nil
|
|
}
|