package localai import ( "encoding/json" "fmt" "github.com/google/uuid" "github.com/labstack/echo/v4" "github.com/mudler/LocalAI/core/config" "github.com/mudler/LocalAI/core/gallery" "github.com/mudler/LocalAI/core/http/middleware" "github.com/mudler/LocalAI/core/schema" "github.com/mudler/LocalAI/core/services/galleryop" "github.com/mudler/LocalAI/pkg/system" "github.com/mudler/xlog" ) type ModelGalleryEndpointService struct { galleries []config.Gallery backendGalleries []config.Gallery modelPath string galleryApplier *galleryop.GalleryService configLoader *config.ModelConfigLoader } type GalleryModel struct { ID string `json:"id"` gallery.GalleryModel } func CreateModelGalleryEndpointService(galleries []config.Gallery, backendGalleries []config.Gallery, systemState *system.SystemState, galleryApplier *galleryop.GalleryService, configLoader *config.ModelConfigLoader) ModelGalleryEndpointService { return ModelGalleryEndpointService{ galleries: galleries, backendGalleries: backendGalleries, modelPath: systemState.Model.ModelsPath, galleryApplier: galleryApplier, configLoader: configLoader, } } // GetOpStatusEndpoint returns the job status // @Summary Returns the job status // @Tags models // @Success 200 {object} galleryop.OpStatus "Response" // @Router /models/jobs/{uuid} [get] func (mgs *ModelGalleryEndpointService) GetOpStatusEndpoint() echo.HandlerFunc { return func(c echo.Context) error { status := mgs.galleryApplier.GetStatus(c.Param("uuid")) if status == nil { return fmt.Errorf("could not find any status for ID") } return c.JSON(200, status) } } // GetAllStatusEndpoint returns all the jobs status progress // @Summary Returns all the jobs status progress // @Tags models // @Success 200 {object} map[string]galleryop.OpStatus "Response" // @Router /models/jobs [get] func (mgs *ModelGalleryEndpointService) GetAllStatusEndpoint() echo.HandlerFunc { return func(c echo.Context) error { return c.JSON(200, mgs.galleryApplier.GetAllStatus()) } } // ApplyModelGalleryEndpoint installs a new model to a LocalAI instance from the model gallery // @Summary Install models to LocalAI. // @Tags models // @Param request body GalleryModel true "query params" // @Success 200 {object} schema.GalleryResponse "Response" // @Router /models/apply [post] func (mgs *ModelGalleryEndpointService) ApplyModelGalleryEndpoint() echo.HandlerFunc { return func(c echo.Context) error { input := new(GalleryModel) // Get input data from the request body if err := c.Bind(input); err != nil { return err } uuid, err := uuid.NewUUID() if err != nil { return err } mgs.galleryApplier.ModelGalleryChannel <- galleryop.ManagementOp[gallery.GalleryModel, gallery.ModelConfig]{ Req: input.GalleryModel, ID: uuid.String(), GalleryElementName: input.ID, Galleries: mgs.galleries, BackendGalleries: mgs.backendGalleries, } return c.JSON(200, schema.GalleryResponse{ID: uuid.String(), StatusURL: fmt.Sprintf("%smodels/jobs/%s", middleware.BaseURL(c), uuid.String())}) } } // DeleteModelGalleryEndpoint lets delete models from a LocalAI instance // @Summary delete models to LocalAI. // @Tags models // @Param name path string true "Model name" // @Success 200 {object} schema.GalleryResponse "Response" // @Router /models/delete/{name} [post] func (mgs *ModelGalleryEndpointService) DeleteModelGalleryEndpoint() echo.HandlerFunc { return func(c echo.Context) error { modelName := c.Param("name") mgs.galleryApplier.ModelGalleryChannel <- galleryop.ManagementOp[gallery.GalleryModel, gallery.ModelConfig]{ Delete: true, GalleryElementName: modelName, } mgs.configLoader.RemoveModelConfig(modelName) uuid, err := uuid.NewUUID() if err != nil { return err } return c.JSON(200, schema.GalleryResponse{ID: uuid.String(), StatusURL: fmt.Sprintf("%smodels/jobs/%s", middleware.BaseURL(c), uuid.String())}) } } // ListModelFromGalleryEndpoint list the available models for installation from the active galleries // @Summary List installable models. // @Tags models // @Success 200 {object} []gallery.Metadata "Response" // @Router /models/available [get] func (mgs *ModelGalleryEndpointService) ListModelFromGalleryEndpoint(systemState *system.SystemState) echo.HandlerFunc { return func(c echo.Context) error { models, err := gallery.AvailableGalleryModels(mgs.galleries, systemState) if err != nil { xlog.Error("could not list models from galleries", "error", err) return err } xlog.Debug("Available models from galleries", "modelCount", len(models), "galleryCount", len(mgs.galleries)) m := []gallery.Metadata{} for _, mm := range models { m = append(m, mm.Metadata) } xlog.Debug("Models", "models", m) dat, err := json.Marshal(m) if err != nil { return fmt.Errorf("could not marshal models: %w", err) } return c.Blob(200, "application/json", dat) } } // ListModelGalleriesEndpoint list the available galleries configured in LocalAI // @Summary List all Galleries // @Tags models // @Success 200 {object} []config.Gallery "Response" // @Router /models/galleries [get] // NOTE: This is different (and much simpler!) than above! This JUST lists the model galleries that have been loaded, not their contents! func (mgs *ModelGalleryEndpointService) ListModelGalleriesEndpoint() echo.HandlerFunc { return func(c echo.Context) error { xlog.Debug("Listing model galleries", "galleries", mgs.galleries) dat, err := json.Marshal(mgs.galleries) if err != nil { return err } return c.Blob(200, "application/json", dat) } }