From 1dbb3b8abcf616408f19b095c0f7c5d43565c5b3 Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Sun, 18 Aug 2024 09:26:29 +0200 Subject: [PATCH] fix(gallery): be consistent and disable UI routes as well (#3262) Signed-off-by: Ettore Di Giacinto --- core/http/routes/ui.go | 297 +++++++++++++++++++++-------------------- 1 file changed, 150 insertions(+), 147 deletions(-) diff --git a/core/http/routes/ui.go b/core/http/routes/ui.go index 0a9867fe641..6dfb3f433df 100644 --- a/core/http/routes/ui.go +++ b/core/http/routes/ui.go @@ -119,185 +119,188 @@ func RegisterUIRoutes(app *fiber.App, }) } - // Show the Models page (all models) - app.Get("/browse", auth, func(c *fiber.Ctx) error { - term := c.Query("term") - - models, _ := gallery.AvailableGalleryModels(appConfig.Galleries, appConfig.ModelPath) - - // Get all available tags - allTags := map[string]struct{}{} - tags := []string{} - for _, m := range models { - for _, t := range m.Tags { - allTags[t] = struct{}{} + if !appConfig.DisableGalleryEndpoint { + + // Show the Models page (all models) + app.Get("/browse", auth, func(c *fiber.Ctx) error { + term := c.Query("term") + + models, _ := gallery.AvailableGalleryModels(appConfig.Galleries, appConfig.ModelPath) + + // Get all available tags + allTags := map[string]struct{}{} + tags := []string{} + for _, m := range models { + for _, t := range m.Tags { + allTags[t] = struct{}{} + } } - } - for t := range allTags { - tags = append(tags, t) - } - sort.Strings(tags) + for t := range allTags { + tags = append(tags, t) + } + sort.Strings(tags) - if term != "" { - models = gallery.GalleryModels(models).Search(term) - } + if term != "" { + models = gallery.GalleryModels(models).Search(term) + } - // Get model statuses - processingModelsData, taskTypes := modelStatus() + // Get model statuses + processingModelsData, taskTypes := modelStatus() - summary := fiber.Map{ - "Title": "LocalAI - Models", - "Version": internal.PrintableVersion(), - "Models": template.HTML(elements.ListModels(models, processingModels, galleryService)), - "Repositories": appConfig.Galleries, - "AllTags": tags, - "ProcessingModels": processingModelsData, - "AvailableModels": len(models), - "IsP2PEnabled": p2p.IsP2PEnabled(), - - "TaskTypes": taskTypes, - // "ApplicationConfig": appConfig, - } + summary := fiber.Map{ + "Title": "LocalAI - Models", + "Version": internal.PrintableVersion(), + "Models": template.HTML(elements.ListModels(models, processingModels, galleryService)), + "Repositories": appConfig.Galleries, + "AllTags": tags, + "ProcessingModels": processingModelsData, + "AvailableModels": len(models), + "IsP2PEnabled": p2p.IsP2PEnabled(), + + "TaskTypes": taskTypes, + // "ApplicationConfig": appConfig, + } - // Render index - return c.Render("views/models", summary) - }) + // Render index + return c.Render("views/models", summary) + }) - // Show the models, filtered from the user input - // https://htmx.org/examples/active-search/ - app.Post("/browse/search/models", auth, func(c *fiber.Ctx) error { - form := struct { - Search string `form:"search"` - }{} - if err := c.BodyParser(&form); err != nil { - return c.Status(fiber.StatusBadRequest).SendString(err.Error()) - } + // Show the models, filtered from the user input + // https://htmx.org/examples/active-search/ + app.Post("/browse/search/models", auth, func(c *fiber.Ctx) error { + form := struct { + Search string `form:"search"` + }{} + if err := c.BodyParser(&form); err != nil { + return c.Status(fiber.StatusBadRequest).SendString(err.Error()) + } - models, _ := gallery.AvailableGalleryModels(appConfig.Galleries, appConfig.ModelPath) + models, _ := gallery.AvailableGalleryModels(appConfig.Galleries, appConfig.ModelPath) - return c.SendString(elements.ListModels(gallery.GalleryModels(models).Search(form.Search), processingModels, galleryService)) - }) + return c.SendString(elements.ListModels(gallery.GalleryModels(models).Search(form.Search), processingModels, galleryService)) + }) - /* + /* - Install routes + Install routes - */ + */ - // This route is used when the "Install" button is pressed, we submit here a new job to the gallery service - // https://htmx.org/examples/progress-bar/ - app.Post("/browse/install/model/:id", auth, func(c *fiber.Ctx) error { - galleryID := strings.Clone(c.Params("id")) // note: strings.Clone is required for multiple requests! - log.Debug().Msgf("UI job submitted to install : %+v\n", galleryID) + // This route is used when the "Install" button is pressed, we submit here a new job to the gallery service + // https://htmx.org/examples/progress-bar/ + app.Post("/browse/install/model/:id", auth, func(c *fiber.Ctx) error { + galleryID := strings.Clone(c.Params("id")) // note: strings.Clone is required for multiple requests! + log.Debug().Msgf("UI job submitted to install : %+v\n", galleryID) - id, err := uuid.NewUUID() - if err != nil { - return err - } + id, err := uuid.NewUUID() + if err != nil { + return err + } - uid := id.String() + uid := id.String() - processingModels.Set(galleryID, uid) + processingModels.Set(galleryID, uid) - op := gallery.GalleryOp{ - Id: uid, - GalleryModelName: galleryID, - Galleries: appConfig.Galleries, - } - go func() { - galleryService.C <- op - }() + op := gallery.GalleryOp{ + Id: uid, + GalleryModelName: galleryID, + Galleries: appConfig.Galleries, + } + go func() { + galleryService.C <- op + }() - return c.SendString(elements.StartProgressBar(uid, "0", "Installation")) - }) + return c.SendString(elements.StartProgressBar(uid, "0", "Installation")) + }) - // This route is used when the "Install" button is pressed, we submit here a new job to the gallery service - // https://htmx.org/examples/progress-bar/ - app.Post("/browse/delete/model/:id", auth, func(c *fiber.Ctx) error { - galleryID := strings.Clone(c.Params("id")) // note: strings.Clone is required for multiple requests! - log.Debug().Msgf("UI job submitted to delete : %+v\n", galleryID) - var galleryName = galleryID - if strings.Contains(galleryID, "@") { - // if the galleryID contains a @ it means that it's a model from a gallery - // but we want to delete it from the local models which does not need - // a repository ID - galleryName = strings.Split(galleryID, "@")[1] - } + // This route is used when the "Install" button is pressed, we submit here a new job to the gallery service + // https://htmx.org/examples/progress-bar/ + app.Post("/browse/delete/model/:id", auth, func(c *fiber.Ctx) error { + galleryID := strings.Clone(c.Params("id")) // note: strings.Clone is required for multiple requests! + log.Debug().Msgf("UI job submitted to delete : %+v\n", galleryID) + var galleryName = galleryID + if strings.Contains(galleryID, "@") { + // if the galleryID contains a @ it means that it's a model from a gallery + // but we want to delete it from the local models which does not need + // a repository ID + galleryName = strings.Split(galleryID, "@")[1] + } - id, err := uuid.NewUUID() - if err != nil { - return err - } + id, err := uuid.NewUUID() + if err != nil { + return err + } - uid := id.String() + uid := id.String() - // Track the deletion job by galleryID and galleryName - // The GalleryID contains information about the repository, - // while the GalleryName is ONLY the name of the model - processingModels.Set(galleryName, uid) - processingModels.Set(galleryID, uid) + // Track the deletion job by galleryID and galleryName + // The GalleryID contains information about the repository, + // while the GalleryName is ONLY the name of the model + processingModels.Set(galleryName, uid) + processingModels.Set(galleryID, uid) - op := gallery.GalleryOp{ - Id: uid, - Delete: true, - GalleryModelName: galleryName, - } - go func() { - galleryService.C <- op - cl.RemoveBackendConfig(galleryName) - }() + op := gallery.GalleryOp{ + Id: uid, + Delete: true, + GalleryModelName: galleryName, + } + go func() { + galleryService.C <- op + cl.RemoveBackendConfig(galleryName) + }() - return c.SendString(elements.StartProgressBar(uid, "0", "Deletion")) - }) + return c.SendString(elements.StartProgressBar(uid, "0", "Deletion")) + }) - // Display the job current progress status - // If the job is done, we trigger the /browse/job/:uid route - // https://htmx.org/examples/progress-bar/ - app.Get("/browse/job/progress/:uid", auth, func(c *fiber.Ctx) error { - jobUID := strings.Clone(c.Params("uid")) // note: strings.Clone is required for multiple requests! + // Display the job current progress status + // If the job is done, we trigger the /browse/job/:uid route + // https://htmx.org/examples/progress-bar/ + app.Get("/browse/job/progress/:uid", auth, func(c *fiber.Ctx) error { + jobUID := strings.Clone(c.Params("uid")) // note: strings.Clone is required for multiple requests! - status := galleryService.GetStatus(jobUID) - if status == nil { - //fmt.Errorf("could not find any status for ID") - return c.SendString(elements.ProgressBar("0")) - } + status := galleryService.GetStatus(jobUID) + if status == nil { + //fmt.Errorf("could not find any status for ID") + return c.SendString(elements.ProgressBar("0")) + } - if status.Progress == 100 { - c.Set("HX-Trigger", "done") // this triggers /browse/job/:uid (which is when the job is done) - return c.SendString(elements.ProgressBar("100")) - } - if status.Error != nil { - // TODO: instead of deleting the job, we should keep it in the cache and make it dismissable by the user - processingModels.DeleteUUID(jobUID) - return c.SendString(elements.ErrorProgress(status.Error.Error(), status.GalleryModelName)) - } + if status.Progress == 100 { + c.Set("HX-Trigger", "done") // this triggers /browse/job/:uid (which is when the job is done) + return c.SendString(elements.ProgressBar("100")) + } + if status.Error != nil { + // TODO: instead of deleting the job, we should keep it in the cache and make it dismissable by the user + processingModels.DeleteUUID(jobUID) + return c.SendString(elements.ErrorProgress(status.Error.Error(), status.GalleryModelName)) + } - return c.SendString(elements.ProgressBar(fmt.Sprint(status.Progress))) - }) + return c.SendString(elements.ProgressBar(fmt.Sprint(status.Progress))) + }) - // this route is hit when the job is done, and we display the - // final state (for now just displays "Installation completed") - app.Get("/browse/job/:uid", auth, func(c *fiber.Ctx) error { - jobUID := strings.Clone(c.Params("uid")) // note: strings.Clone is required for multiple requests! + // this route is hit when the job is done, and we display the + // final state (for now just displays "Installation completed") + app.Get("/browse/job/:uid", auth, func(c *fiber.Ctx) error { + jobUID := strings.Clone(c.Params("uid")) // note: strings.Clone is required for multiple requests! - status := galleryService.GetStatus(jobUID) + status := galleryService.GetStatus(jobUID) - galleryID := "" - processingModels.DeleteUUID(jobUID) - if galleryID == "" { - log.Debug().Msgf("no processing model found for job : %+v\n", jobUID) - } + galleryID := "" + processingModels.DeleteUUID(jobUID) + if galleryID == "" { + log.Debug().Msgf("no processing model found for job : %+v\n", jobUID) + } - log.Debug().Msgf("JOB finished : %+v\n", status) - showDelete := true - displayText := "Installation completed" - if status.Deletion { - showDelete = false - displayText = "Deletion completed" - } + log.Debug().Msgf("JOB finished : %+v\n", status) + showDelete := true + displayText := "Installation completed" + if status.Deletion { + showDelete = false + displayText = "Deletion completed" + } - return c.SendString(elements.DoneProgress(galleryID, displayText, showDelete)) - }) + return c.SendString(elements.DoneProgress(galleryID, displayText, showDelete)) + }) + } // Show the Chat page app.Get("/chat/:model", auth, func(c *fiber.Ctx) error {