Spaces:
Configuration error
Configuration error
package startup | |
import ( | |
"fmt" | |
"os" | |
"github.com/mudler/LocalAI/core" | |
"github.com/mudler/LocalAI/core/backend" | |
"github.com/mudler/LocalAI/core/config" | |
"github.com/mudler/LocalAI/core/services" | |
"github.com/mudler/LocalAI/internal" | |
"github.com/mudler/LocalAI/pkg/assets" | |
"github.com/mudler/LocalAI/pkg/library" | |
"github.com/mudler/LocalAI/pkg/model" | |
pkgStartup "github.com/mudler/LocalAI/pkg/startup" | |
"github.com/mudler/LocalAI/pkg/xsysinfo" | |
"github.com/rs/zerolog/log" | |
) | |
func Startup(opts ...config.AppOption) (*config.BackendConfigLoader, *model.ModelLoader, *config.ApplicationConfig, error) { | |
options := config.NewApplicationConfig(opts...) | |
log.Info().Msgf("Starting LocalAI using %d threads, with models path: %s", options.Threads, options.ModelPath) | |
log.Info().Msgf("LocalAI version: %s", internal.PrintableVersion()) | |
caps, err := xsysinfo.CPUCapabilities() | |
if err == nil { | |
log.Debug().Msgf("CPU capabilities: %v", caps) | |
} | |
gpus, err := xsysinfo.GPUs() | |
if err == nil { | |
log.Debug().Msgf("GPU count: %d", len(gpus)) | |
for _, gpu := range gpus { | |
log.Debug().Msgf("GPU: %s", gpu.String()) | |
} | |
} | |
// Make sure directories exists | |
if options.ModelPath == "" { | |
return nil, nil, nil, fmt.Errorf("options.ModelPath cannot be empty") | |
} | |
err = os.MkdirAll(options.ModelPath, 0750) | |
if err != nil { | |
return nil, nil, nil, fmt.Errorf("unable to create ModelPath: %q", err) | |
} | |
if options.ImageDir != "" { | |
err := os.MkdirAll(options.ImageDir, 0750) | |
if err != nil { | |
return nil, nil, nil, fmt.Errorf("unable to create ImageDir: %q", err) | |
} | |
} | |
if options.AudioDir != "" { | |
err := os.MkdirAll(options.AudioDir, 0750) | |
if err != nil { | |
return nil, nil, nil, fmt.Errorf("unable to create AudioDir: %q", err) | |
} | |
} | |
if options.UploadDir != "" { | |
err := os.MkdirAll(options.UploadDir, 0750) | |
if err != nil { | |
return nil, nil, nil, fmt.Errorf("unable to create UploadDir: %q", err) | |
} | |
} | |
if err := pkgStartup.InstallModels(options.Galleries, options.ModelLibraryURL, options.ModelPath, options.EnforcePredownloadScans, nil, options.ModelsURL...); err != nil { | |
log.Error().Err(err).Msg("error installing models") | |
} | |
cl := config.NewBackendConfigLoader(options.ModelPath) | |
ml := model.NewModelLoader(options.ModelPath) | |
configLoaderOpts := options.ToConfigLoaderOptions() | |
if err := cl.LoadBackendConfigsFromPath(options.ModelPath, configLoaderOpts...); err != nil { | |
log.Error().Err(err).Msg("error loading config files") | |
} | |
if options.ConfigFile != "" { | |
if err := cl.LoadMultipleBackendConfigsSingleFile(options.ConfigFile, configLoaderOpts...); err != nil { | |
log.Error().Err(err).Msg("error loading config file") | |
} | |
} | |
if err := cl.Preload(options.ModelPath); err != nil { | |
log.Error().Err(err).Msg("error downloading models") | |
} | |
if options.PreloadJSONModels != "" { | |
if err := services.ApplyGalleryFromString(options.ModelPath, options.PreloadJSONModels, options.EnforcePredownloadScans, options.Galleries); err != nil { | |
return nil, nil, nil, err | |
} | |
} | |
if options.PreloadModelsFromPath != "" { | |
if err := services.ApplyGalleryFromFile(options.ModelPath, options.PreloadModelsFromPath, options.EnforcePredownloadScans, options.Galleries); err != nil { | |
return nil, nil, nil, err | |
} | |
} | |
if options.Debug { | |
for _, v := range cl.GetAllBackendConfigs() { | |
log.Debug().Msgf("Model: %s (config: %+v)", v.Name, v) | |
} | |
} | |
if options.AssetsDestination != "" { | |
// Extract files from the embedded FS | |
err := assets.ExtractFiles(options.BackendAssets, options.AssetsDestination) | |
log.Debug().Msgf("Extracting backend assets files to %s", options.AssetsDestination) | |
if err != nil { | |
log.Warn().Msgf("Failed extracting backend assets files: %s (might be required for some backends to work properly)", err) | |
} | |
} | |
if options.LibPath != "" { | |
// If there is a lib directory, set LD_LIBRARY_PATH to include it | |
err := library.LoadExternal(options.LibPath) | |
if err != nil { | |
log.Error().Err(err).Str("LibPath", options.LibPath).Msg("Error while loading external libraries") | |
} | |
} | |
// turn off any process that was started by GRPC if the context is canceled | |
go func() { | |
<-options.Context.Done() | |
log.Debug().Msgf("Context canceled, shutting down") | |
err := ml.StopAllGRPC() | |
if err != nil { | |
log.Error().Err(err).Msg("error while stopping all grpc backends") | |
} | |
}() | |
if options.WatchDog { | |
wd := model.NewWatchDog( | |
ml, | |
options.WatchDogBusyTimeout, | |
options.WatchDogIdleTimeout, | |
options.WatchDogBusy, | |
options.WatchDogIdle) | |
ml.SetWatchDog(wd) | |
go wd.Run() | |
go func() { | |
<-options.Context.Done() | |
log.Debug().Msgf("Context canceled, shutting down") | |
wd.Shutdown() | |
}() | |
} | |
if options.LoadToMemory != nil { | |
for _, m := range options.LoadToMemory { | |
cfg, err := cl.LoadBackendConfigFileByName(m, options.ModelPath, | |
config.LoadOptionDebug(options.Debug), | |
config.LoadOptionThreads(options.Threads), | |
config.LoadOptionContextSize(options.ContextSize), | |
config.LoadOptionF16(options.F16), | |
config.ModelPath(options.ModelPath), | |
) | |
if err != nil { | |
return nil, nil, nil, err | |
} | |
log.Debug().Msgf("Auto loading model %s into memory from file: %s", m, cfg.Model) | |
o := backend.ModelOptions(*cfg, options, []model.Option{}) | |
var backendErr error | |
if cfg.Backend != "" { | |
o = append(o, model.WithBackendString(cfg.Backend)) | |
_, backendErr = ml.BackendLoader(o...) | |
} else { | |
_, backendErr = ml.GreedyLoader(o...) | |
} | |
if backendErr != nil { | |
return nil, nil, nil, err | |
} | |
} | |
} | |
// Watch the configuration directory | |
startWatcher(options) | |
log.Info().Msg("core/startup process completed!") | |
return cl, ml, options, nil | |
} | |
func startWatcher(options *config.ApplicationConfig) { | |
if options.DynamicConfigsDir == "" { | |
// No need to start the watcher if the directory is not set | |
return | |
} | |
if _, err := os.Stat(options.DynamicConfigsDir); err != nil { | |
if os.IsNotExist(err) { | |
// We try to create the directory if it does not exist and was specified | |
if err := os.MkdirAll(options.DynamicConfigsDir, 0700); err != nil { | |
log.Error().Err(err).Msg("failed creating DynamicConfigsDir") | |
} | |
} else { | |
// something else happened, we log the error and don't start the watcher | |
log.Error().Err(err).Msg("failed to read DynamicConfigsDir, watcher will not be started") | |
return | |
} | |
} | |
configHandler := newConfigFileHandler(options) | |
if err := configHandler.Watch(); err != nil { | |
log.Error().Err(err).Msg("failed creating watcher") | |
} | |
} | |
// In Lieu of a proper DI framework, this function wires up the Application manually. | |
// This is in core/startup rather than core/state.go to keep package references clean! | |
func createApplication(appConfig *config.ApplicationConfig) *core.Application { | |
app := &core.Application{ | |
ApplicationConfig: appConfig, | |
BackendConfigLoader: config.NewBackendConfigLoader(appConfig.ModelPath), | |
ModelLoader: model.NewModelLoader(appConfig.ModelPath), | |
} | |
var err error | |
// app.EmbeddingsBackendService = backend.NewEmbeddingsBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig) | |
// app.ImageGenerationBackendService = backend.NewImageGenerationBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig) | |
// app.LLMBackendService = backend.NewLLMBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig) | |
// app.TranscriptionBackendService = backend.NewTranscriptionBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig) | |
// app.TextToSpeechBackendService = backend.NewTextToSpeechBackendService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig) | |
app.BackendMonitorService = services.NewBackendMonitorService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig) | |
app.GalleryService = services.NewGalleryService(app.ApplicationConfig) | |
// app.OpenAIService = services.NewOpenAIService(app.ModelLoader, app.BackendConfigLoader, app.ApplicationConfig, app.LLMBackendService) | |
app.LocalAIMetricsService, err = services.NewLocalAIMetricsService() | |
if err != nil { | |
log.Error().Err(err).Msg("encountered an error initializing metrics service, startup will continue but metrics will not be tracked.") | |
} | |
return app | |
} | |