diff --git a/core/config/application_config.go b/core/config/application_config.go index c2d4e13a..49b35f97 100644 --- a/core/config/application_config.go +++ b/core/config/application_config.go @@ -15,6 +15,7 @@ type ApplicationConfig struct { ConfigFile string ModelPath string UploadLimitMB, Threads, ContextSize int + DisableWelcomePage bool F16 bool Debug, DisableMessage bool ImageDir string @@ -105,6 +106,10 @@ var EnableWatchDogBusyCheck = func(o *ApplicationConfig) { o.WatchDogBusy = true } +var DisableWelcomePage = func(o *ApplicationConfig) { + o.DisableWelcomePage = true +} + func SetWatchDogBusyTimeout(t time.Duration) AppOption { return func(o *ApplicationConfig) { o.WatchDogBusyTimeout = t diff --git a/core/http/api.go b/core/http/api.go index de0a4939..365407d8 100644 --- a/core/http/api.go +++ b/core/http/api.go @@ -1,12 +1,15 @@ package http import ( + "embed" "encoding/json" "errors" - "github.com/go-skynet/LocalAI/pkg/utils" + "net/http" "os" "strings" + "github.com/go-skynet/LocalAI/pkg/utils" + "github.com/go-skynet/LocalAI/core/http/endpoints/elevenlabs" "github.com/go-skynet/LocalAI/core/http/endpoints/localai" "github.com/go-skynet/LocalAI/core/http/endpoints/openai" @@ -21,6 +24,7 @@ import ( "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/fiber/v2/middleware/recover" + "github.com/gofiber/template/html/v2" ) func readAuthHeader(c *fiber.Ctx) string { @@ -41,9 +45,14 @@ func readAuthHeader(c *fiber.Ctx) string { return authHeader } +//go:embed views/* +var viewsfs embed.FS + func App(cl *config.BackendConfigLoader, ml *model.ModelLoader, appConfig *config.ApplicationConfig) (*fiber.App, error) { + engine := html.NewFileSystem(http.FS(viewsfs), ".html") // Return errors as JSON responses app := fiber.New(fiber.Config{ + Views: engine, BodyLimit: appConfig.UploadLimitMB * 1024 * 1024, // this is the default limit of 4MB DisableStartupMessage: appConfig.DisableMessage, // Override default error handler @@ -168,6 +177,21 @@ func App(cl *config.BackendConfigLoader, ml *model.ModelLoader, appConfig *confi utils.LoadConfig(appConfig.ConfigsDir, openai.AssistantsConfigFile, &openai.Assistants) utils.LoadConfig(appConfig.ConfigsDir, openai.AssistantsFileConfigFile, &openai.AssistantFiles) + if !appConfig.DisableWelcomePage { + models, _ := ml.ListModels() + backendConfigs := cl.GetAllBackendConfigs() + app.Get("/", auth, func(c *fiber.Ctx) error { + // Render index + return c.Render("views/index", fiber.Map{ + "Title": "LocalAI API - " + internal.PrintableVersion(), + "Version": internal.PrintableVersion(), + "Models": models, + "ModelsConfig": backendConfigs, + "ApplicationConfig": appConfig, + }) + }) + } + modelGalleryEndpointService := localai.CreateModelGalleryEndpointService(appConfig.Galleries, appConfig.ModelPath, galleryService) app.Post("/models/apply", auth, modelGalleryEndpointService.ApplyModelGalleryEndpoint()) app.Get("/models/available", auth, modelGalleryEndpointService.ListModelFromGalleryEndpoint()) @@ -275,5 +299,21 @@ func App(cl *config.BackendConfigLoader, ml *model.ModelLoader, appConfig *confi app.Get("/metrics", localai.LocalAIMetricsEndpoint()) + // Define a custom 404 handler + app.Use(func(c *fiber.Ctx) error { + + // Check if the request accepts JSON + if string(c.Context().Request.Header.ContentType()) == "application/json" || len(c.Accepts("html")) == 0 { + // The client expects a JSON response + c.Status(fiber.StatusNotFound).JSON(fiber.Map{ + "error": "Resource not found", + }) + } else { + // The client expects an HTML response + c.Status(fiber.StatusNotFound).Render("views/404", fiber.Map{}) + } + return nil + }) + return app, nil } diff --git a/core/http/views/404.html b/core/http/views/404.html new file mode 100644 index 00000000..359d8505 --- /dev/null +++ b/core/http/views/404.html @@ -0,0 +1,33 @@ + + + +{{template "views/partials/head" .}} + +
+The FOSS alternative to OpenAI, Claude, ...
+ Documentation +The FOSS alternative to OpenAI, Claude, ...
+ Documentation +We have {{len .ModelsConfig}} pre-loaded models available.
+{{.Name}}
+ {{ if .Usage }} +{{.Usage}}
{{.Description}}
+ {{ end }} +