Merge branch 'master' of github.com:Saavrm26/LocalAI into resume_download

This commit is contained in:
Saarthak Verma 2025-01-08 23:30:21 +05:30
commit a17c9e3718
No known key found for this signature in database
GPG key ID: 2BEFA9EF09A35950
41 changed files with 633 additions and 114 deletions

View file

@ -8,7 +8,7 @@ DETECT_LIBS?=true
# llama.cpp versions # llama.cpp versions
GOLLAMA_REPO?=https://github.com/go-skynet/go-llama.cpp GOLLAMA_REPO?=https://github.com/go-skynet/go-llama.cpp
GOLLAMA_VERSION?=2b57a8ae43e4699d3dc5d1496a1ccd42922993be GOLLAMA_VERSION?=2b57a8ae43e4699d3dc5d1496a1ccd42922993be
CPPLLAMA_VERSION?=9394bbd484f802ce80d2858033583af3ef700d25 CPPLLAMA_VERSION?=53ff6b9b9fb25ed0ec0a213e05534fe7c3d0040f
# whisper.cpp version # whisper.cpp version
WHISPER_REPO?=https://github.com/ggerganov/whisper.cpp WHISPER_REPO?=https://github.com/ggerganov/whisper.cpp

View file

@ -87,6 +87,8 @@ func API(application *application.Application) (*fiber.App, error) {
router := fiber.New(fiberCfg) router := fiber.New(fiberCfg)
router.Use(middleware.StripPathPrefix())
router.Hooks().OnListen(func(listenData fiber.ListenData) error { router.Hooks().OnListen(func(listenData fiber.ListenData) error {
scheme := "http" scheme := "http"
if listenData.TLS { if listenData.TLS {

View file

@ -237,6 +237,31 @@ func postInvalidRequest(url string) (error, int) {
return nil, resp.StatusCode return nil, resp.StatusCode
} }
func getRequest(url string, header http.Header) (error, int, []byte) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return err, -1, nil
}
req.Header = header
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err, -1, nil
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return err, -1, nil
}
return nil, resp.StatusCode, body
}
const bertEmbeddingsURL = `https://gist.githubusercontent.com/mudler/0a080b166b87640e8644b09c2aee6e3b/raw/f0e8c26bb72edc16d9fbafbfd6638072126ff225/bert-embeddings-gallery.yaml` const bertEmbeddingsURL = `https://gist.githubusercontent.com/mudler/0a080b166b87640e8644b09c2aee6e3b/raw/f0e8c26bb72edc16d9fbafbfd6638072126ff225/bert-embeddings-gallery.yaml`
//go:embed backend-assets/* //go:embed backend-assets/*
@ -345,6 +370,33 @@ var _ = Describe("API test", func() {
}) })
}) })
Context("URL routing Tests", func() {
It("Should support reverse-proxy when unauthenticated", func() {
err, sc, body := getRequest("http://127.0.0.1:9090/myprefix/", http.Header{
"X-Forwarded-Proto": {"https"},
"X-Forwarded-Host": {"example.org"},
"X-Forwarded-Prefix": {"/myprefix/"},
})
Expect(err).To(BeNil(), "error")
Expect(sc).To(Equal(401), "status code")
Expect(string(body)).To(ContainSubstring(`<base href="https://example.org/myprefix/" />`), "body")
})
It("Should support reverse-proxy when authenticated", func() {
err, sc, body := getRequest("http://127.0.0.1:9090/myprefix/", http.Header{
"Authorization": {bearerKey},
"X-Forwarded-Proto": {"https"},
"X-Forwarded-Host": {"example.org"},
"X-Forwarded-Prefix": {"/myprefix/"},
})
Expect(err).To(BeNil(), "error")
Expect(sc).To(Equal(200), "status code")
Expect(string(body)).To(ContainSubstring(`<base href="https://example.org/myprefix/" />`), "body")
})
})
Context("Applying models", func() { Context("Applying models", func() {
It("applies models from a gallery", func() { It("applies models from a gallery", func() {

View file

@ -16,7 +16,7 @@ func installButton(galleryName string) elem.Node {
"class": "float-right inline-block rounded bg-primary px-6 pb-2.5 mb-3 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong", "class": "float-right inline-block rounded bg-primary px-6 pb-2.5 mb-3 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong",
"hx-swap": "outerHTML", "hx-swap": "outerHTML",
// post the Model ID as param // post the Model ID as param
"hx-post": "/browse/install/model/" + galleryName, "hx-post": "browse/install/model/" + galleryName,
}, },
elem.I( elem.I(
attrs.Props{ attrs.Props{
@ -36,7 +36,7 @@ func reInstallButton(galleryName string) elem.Node {
"hx-target": "#action-div-" + dropBadChars(galleryName), "hx-target": "#action-div-" + dropBadChars(galleryName),
"hx-swap": "outerHTML", "hx-swap": "outerHTML",
// post the Model ID as param // post the Model ID as param
"hx-post": "/browse/install/model/" + galleryName, "hx-post": "browse/install/model/" + galleryName,
}, },
elem.I( elem.I(
attrs.Props{ attrs.Props{
@ -80,7 +80,7 @@ func deleteButton(galleryID string) elem.Node {
"hx-target": "#action-div-" + dropBadChars(galleryID), "hx-target": "#action-div-" + dropBadChars(galleryID),
"hx-swap": "outerHTML", "hx-swap": "outerHTML",
// post the Model ID as param // post the Model ID as param
"hx-post": "/browse/delete/model/" + galleryID, "hx-post": "browse/delete/model/" + galleryID,
}, },
elem.I( elem.I(
attrs.Props{ attrs.Props{

View file

@ -47,7 +47,7 @@ func searchableElement(text, icon string) elem.Node {
// "value": text, // "value": text,
//"class": "inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2", //"class": "inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2",
"href": "#!", "href": "#!",
"hx-post": "/browse/search/models", "hx-post": "browse/search/models",
"hx-target": "#search-results", "hx-target": "#search-results",
// TODO: this doesn't work // TODO: this doesn't work
// "hx-vals": `{ \"search\": \"` + text + `\" }`, // "hx-vals": `{ \"search\": \"` + text + `\" }`,

View file

@ -64,7 +64,7 @@ func StartProgressBar(uid, progress, text string) string {
return elem.Div( return elem.Div(
attrs.Props{ attrs.Props{
"hx-trigger": "done", "hx-trigger": "done",
"hx-get": "/browse/job/" + uid, "hx-get": "browse/job/" + uid,
"hx-swap": "outerHTML", "hx-swap": "outerHTML",
"hx-target": "this", "hx-target": "this",
}, },
@ -77,7 +77,7 @@ func StartProgressBar(uid, progress, text string) string {
}, },
elem.Text(bluemonday.StrictPolicy().Sanitize(text)), //Perhaps overly defensive elem.Text(bluemonday.StrictPolicy().Sanitize(text)), //Perhaps overly defensive
elem.Div(attrs.Props{ elem.Div(attrs.Props{
"hx-get": "/browse/job/progress/" + uid, "hx-get": "browse/job/progress/" + uid,
"hx-trigger": "every 600ms", "hx-trigger": "every 600ms",
"hx-target": "this", "hx-target": "this",
"hx-swap": "innerHTML", "hx-swap": "innerHTML",

View file

@ -6,6 +6,7 @@ import (
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"github.com/mudler/LocalAI/core/explorer" "github.com/mudler/LocalAI/core/explorer"
"github.com/mudler/LocalAI/core/http/utils"
"github.com/mudler/LocalAI/internal" "github.com/mudler/LocalAI/internal"
) )
@ -14,6 +15,7 @@ func Dashboard() func(*fiber.Ctx) error {
summary := fiber.Map{ summary := fiber.Map{
"Title": "LocalAI API - " + internal.PrintableVersion(), "Title": "LocalAI API - " + internal.PrintableVersion(),
"Version": internal.PrintableVersion(), "Version": internal.PrintableVersion(),
"BaseURL": utils.BaseURL(c),
} }
if string(c.Context().Request.Header.ContentType()) == "application/json" || len(c.Accepts("html")) == 0 { if string(c.Context().Request.Header.ContentType()) == "application/json" || len(c.Accepts("html")) == 0 {

View file

@ -9,6 +9,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/mudler/LocalAI/core/config" "github.com/mudler/LocalAI/core/config"
"github.com/mudler/LocalAI/core/gallery" "github.com/mudler/LocalAI/core/gallery"
"github.com/mudler/LocalAI/core/http/utils"
"github.com/mudler/LocalAI/core/schema" "github.com/mudler/LocalAI/core/schema"
"github.com/mudler/LocalAI/core/services" "github.com/mudler/LocalAI/core/services"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
@ -82,7 +83,8 @@ func (mgs *ModelGalleryEndpointService) ApplyModelGalleryEndpoint() func(c *fibe
Galleries: mgs.galleries, Galleries: mgs.galleries,
ConfigURL: input.ConfigURL, ConfigURL: input.ConfigURL,
} }
return c.JSON(schema.GalleryResponse{ID: uuid.String(), StatusURL: c.BaseURL() + "/models/jobs/" + uuid.String()})
return c.JSON(schema.GalleryResponse{ID: uuid.String(), StatusURL: fmt.Sprintf("%smodels/jobs/%s", utils.BaseURL(c), uuid.String())})
} }
} }
@ -105,7 +107,7 @@ func (mgs *ModelGalleryEndpointService) DeleteModelGalleryEndpoint() func(c *fib
return err return err
} }
return c.JSON(schema.GalleryResponse{ID: uuid.String(), StatusURL: c.BaseURL() + "/models/jobs/" + uuid.String()}) return c.JSON(schema.GalleryResponse{ID: uuid.String(), StatusURL: fmt.Sprintf("%smodels/jobs/%s", utils.BaseURL(c), uuid.String())})
} }
} }

View file

@ -4,6 +4,7 @@ import (
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"github.com/mudler/LocalAI/core/config" "github.com/mudler/LocalAI/core/config"
"github.com/mudler/LocalAI/core/gallery" "github.com/mudler/LocalAI/core/gallery"
"github.com/mudler/LocalAI/core/http/utils"
"github.com/mudler/LocalAI/core/p2p" "github.com/mudler/LocalAI/core/p2p"
"github.com/mudler/LocalAI/core/services" "github.com/mudler/LocalAI/core/services"
"github.com/mudler/LocalAI/internal" "github.com/mudler/LocalAI/internal"
@ -32,6 +33,7 @@ func WelcomeEndpoint(appConfig *config.ApplicationConfig,
summary := fiber.Map{ summary := fiber.Map{
"Title": "LocalAI API - " + internal.PrintableVersion(), "Title": "LocalAI API - " + internal.PrintableVersion(),
"Version": internal.PrintableVersion(), "Version": internal.PrintableVersion(),
"BaseURL": utils.BaseURL(c),
"Models": modelsWithoutConfig, "Models": modelsWithoutConfig,
"ModelsConfig": backendConfigs, "ModelsConfig": backendConfigs,
"GalleryConfig": galleryConfigs, "GalleryConfig": galleryConfigs,

View file

@ -7,6 +7,7 @@ import (
"github.com/gofiber/fiber/v2/middleware/favicon" "github.com/gofiber/fiber/v2/middleware/favicon"
"github.com/gofiber/fiber/v2/middleware/filesystem" "github.com/gofiber/fiber/v2/middleware/filesystem"
"github.com/mudler/LocalAI/core/explorer" "github.com/mudler/LocalAI/core/explorer"
"github.com/mudler/LocalAI/core/http/middleware"
"github.com/mudler/LocalAI/core/http/routes" "github.com/mudler/LocalAI/core/http/routes"
) )
@ -22,6 +23,7 @@ func Explorer(db *explorer.Database) *fiber.App {
app := fiber.New(fiberCfg) app := fiber.New(fiberCfg)
app.Use(middleware.StripPathPrefix())
routes.RegisterExplorerRoutes(app, db) routes.RegisterExplorerRoutes(app, db)
httpFS := http.FS(embedDirStatic) httpFS := http.FS(embedDirStatic)

View file

@ -8,6 +8,7 @@ import (
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/keyauth" "github.com/gofiber/fiber/v2/middleware/keyauth"
"github.com/mudler/LocalAI/core/config" "github.com/mudler/LocalAI/core/config"
"github.com/mudler/LocalAI/core/http/utils"
) )
// This file contains the configuration generators and handler functions that are used along with the fiber/keyauth middleware // This file contains the configuration generators and handler functions that are used along with the fiber/keyauth middleware
@ -39,7 +40,9 @@ func getApiKeyErrorHandler(applicationConfig *config.ApplicationConfig) fiber.Er
if applicationConfig.OpaqueErrors { if applicationConfig.OpaqueErrors {
return ctx.SendStatus(401) return ctx.SendStatus(401)
} }
return ctx.Status(401).Render("views/login", nil) return ctx.Status(401).Render("views/login", fiber.Map{
"BaseURL": utils.BaseURL(ctx),
})
} }
if applicationConfig.OpaqueErrors { if applicationConfig.OpaqueErrors {
return ctx.SendStatus(500) return ctx.SendStatus(500)

View file

@ -0,0 +1,36 @@
package middleware
import (
"strings"
"github.com/gofiber/fiber/v2"
)
// StripPathPrefix returns a middleware that strips a path prefix from the request path.
// The path prefix is obtained from the X-Forwarded-Prefix HTTP request header.
func StripPathPrefix() fiber.Handler {
return func(c *fiber.Ctx) error {
for _, prefix := range c.GetReqHeaders()["X-Forwarded-Prefix"] {
if prefix != "" {
path := c.Path()
pos := len(prefix)
if prefix[pos-1] == '/' {
pos--
} else {
prefix += "/"
}
if strings.HasPrefix(path, prefix) {
c.Path(path[pos:])
break
} else if prefix[:pos] == path {
c.Redirect(prefix)
return nil
}
}
}
return c.Next()
}
}

View file

@ -0,0 +1,121 @@
package middleware
import (
"net/http/httptest"
"testing"
"github.com/gofiber/fiber/v2"
"github.com/stretchr/testify/require"
)
func TestStripPathPrefix(t *testing.T) {
var actualPath string
app := fiber.New()
app.Use(StripPathPrefix())
app.Get("/hello/world", func(c *fiber.Ctx) error {
actualPath = c.Path()
return nil
})
app.Get("/", func(c *fiber.Ctx) error {
actualPath = c.Path()
return nil
})
for _, tc := range []struct {
name string
path string
prefixHeader []string
expectStatus int
expectPath string
}{
{
name: "without prefix and header",
path: "/hello/world",
expectStatus: 200,
expectPath: "/hello/world",
},
{
name: "without prefix and headers on root path",
path: "/",
expectStatus: 200,
expectPath: "/",
},
{
name: "without prefix but header",
path: "/hello/world",
prefixHeader: []string{"/otherprefix/"},
expectStatus: 200,
expectPath: "/hello/world",
},
{
name: "with prefix but non-matching header",
path: "/prefix/hello/world",
prefixHeader: []string{"/otherprefix/"},
expectStatus: 404,
},
{
name: "with prefix and matching header",
path: "/myprefix/hello/world",
prefixHeader: []string{"/myprefix/"},
expectStatus: 200,
expectPath: "/hello/world",
},
{
name: "with prefix and 1st header matching",
path: "/myprefix/hello/world",
prefixHeader: []string{"/myprefix/", "/otherprefix/"},
expectStatus: 200,
expectPath: "/hello/world",
},
{
name: "with prefix and 2nd header matching",
path: "/myprefix/hello/world",
prefixHeader: []string{"/otherprefix/", "/myprefix/"},
expectStatus: 200,
expectPath: "/hello/world",
},
{
name: "with prefix and header not ending with slash",
path: "/myprefix/hello/world",
prefixHeader: []string{"/myprefix"},
expectStatus: 200,
expectPath: "/hello/world",
},
{
name: "with prefix and non-matching header not ending with slash",
path: "/myprefix-suffix/hello/world",
prefixHeader: []string{"/myprefix"},
expectStatus: 404,
},
{
name: "redirect when prefix does not end with a slash",
path: "/myprefix",
prefixHeader: []string{"/myprefix"},
expectStatus: 302,
expectPath: "/myprefix/",
},
} {
t.Run(tc.name, func(t *testing.T) {
actualPath = ""
req := httptest.NewRequest("GET", tc.path, nil)
if tc.prefixHeader != nil {
req.Header["X-Forwarded-Prefix"] = tc.prefixHeader
}
resp, err := app.Test(req, -1)
require.NoError(t, err)
require.Equal(t, tc.expectStatus, resp.StatusCode, "response status code")
if tc.expectStatus == 200 {
require.Equal(t, tc.expectPath, actualPath, "rewritten path")
} else if tc.expectStatus == 302 {
require.Equal(t, tc.expectPath, resp.Header.Get("Location"), "redirect location")
}
})
}
}

View file

@ -10,6 +10,7 @@ import (
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
fiberhtml "github.com/gofiber/template/html/v2" fiberhtml "github.com/gofiber/template/html/v2"
"github.com/microcosm-cc/bluemonday" "github.com/microcosm-cc/bluemonday"
"github.com/mudler/LocalAI/core/http/utils"
"github.com/mudler/LocalAI/core/schema" "github.com/mudler/LocalAI/core/schema"
"github.com/russross/blackfriday" "github.com/russross/blackfriday"
) )
@ -26,7 +27,9 @@ func notFoundHandler(c *fiber.Ctx) error {
}) })
} else { } else {
// The client expects an HTML response // The client expects an HTML response
return c.Status(fiber.StatusNotFound).Render("views/404", fiber.Map{}) return c.Status(fiber.StatusNotFound).Render("views/404", fiber.Map{
"BaseURL": utils.BaseURL(c),
})
} }
} }

View file

@ -6,20 +6,21 @@ import (
"sort" "sort"
"strings" "strings"
"github.com/microcosm-cc/bluemonday"
"github.com/mudler/LocalAI/core/config" "github.com/mudler/LocalAI/core/config"
"github.com/mudler/LocalAI/core/gallery" "github.com/mudler/LocalAI/core/gallery"
"github.com/mudler/LocalAI/core/http/elements" "github.com/mudler/LocalAI/core/http/elements"
"github.com/mudler/LocalAI/core/http/endpoints/localai" "github.com/mudler/LocalAI/core/http/endpoints/localai"
"github.com/mudler/LocalAI/core/http/utils"
"github.com/mudler/LocalAI/core/p2p" "github.com/mudler/LocalAI/core/p2p"
"github.com/mudler/LocalAI/core/services" "github.com/mudler/LocalAI/core/services"
"github.com/mudler/LocalAI/internal" "github.com/mudler/LocalAI/internal"
"github.com/mudler/LocalAI/pkg/model" "github.com/mudler/LocalAI/pkg/model"
"github.com/mudler/LocalAI/pkg/xsync" "github.com/mudler/LocalAI/pkg/xsync"
"github.com/rs/zerolog/log"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/microcosm-cc/bluemonday"
"github.com/rs/zerolog/log"
) )
type modelOpCache struct { type modelOpCache struct {
@ -91,6 +92,7 @@ func RegisterUIRoutes(app *fiber.App,
app.Get("/p2p", func(c *fiber.Ctx) error { app.Get("/p2p", func(c *fiber.Ctx) error {
summary := fiber.Map{ summary := fiber.Map{
"Title": "LocalAI - P2P dashboard", "Title": "LocalAI - P2P dashboard",
"BaseURL": utils.BaseURL(c),
"Version": internal.PrintableVersion(), "Version": internal.PrintableVersion(),
//"Nodes": p2p.GetAvailableNodes(""), //"Nodes": p2p.GetAvailableNodes(""),
//"FederatedNodes": p2p.GetAvailableNodes(p2p.FederatedID), //"FederatedNodes": p2p.GetAvailableNodes(p2p.FederatedID),
@ -149,6 +151,7 @@ func RegisterUIRoutes(app *fiber.App,
summary := fiber.Map{ summary := fiber.Map{
"Title": "LocalAI - Models", "Title": "LocalAI - Models",
"BaseURL": utils.BaseURL(c),
"Version": internal.PrintableVersion(), "Version": internal.PrintableVersion(),
"Models": template.HTML(elements.ListModels(models, processingModels, galleryService)), "Models": template.HTML(elements.ListModels(models, processingModels, galleryService)),
"Repositories": appConfig.Galleries, "Repositories": appConfig.Galleries,
@ -308,6 +311,7 @@ func RegisterUIRoutes(app *fiber.App,
summary := fiber.Map{ summary := fiber.Map{
"Title": "LocalAI - Chat with " + c.Params("model"), "Title": "LocalAI - Chat with " + c.Params("model"),
"BaseURL": utils.BaseURL(c),
"ModelsConfig": backendConfigs, "ModelsConfig": backendConfigs,
"Model": c.Params("model"), "Model": c.Params("model"),
"Version": internal.PrintableVersion(), "Version": internal.PrintableVersion(),
@ -323,11 +327,12 @@ func RegisterUIRoutes(app *fiber.App,
if len(backendConfigs) == 0 { if len(backendConfigs) == 0 {
// If no model is available redirect to the index which suggests how to install models // If no model is available redirect to the index which suggests how to install models
return c.Redirect("/") return c.Redirect(utils.BaseURL(c))
} }
summary := fiber.Map{ summary := fiber.Map{
"Title": "LocalAI - Talk", "Title": "LocalAI - Talk",
"BaseURL": utils.BaseURL(c),
"ModelsConfig": backendConfigs, "ModelsConfig": backendConfigs,
"Model": backendConfigs[0], "Model": backendConfigs[0],
"IsP2PEnabled": p2p.IsP2PEnabled(), "IsP2PEnabled": p2p.IsP2PEnabled(),
@ -344,11 +349,12 @@ func RegisterUIRoutes(app *fiber.App,
if len(backendConfigs) == 0 { if len(backendConfigs) == 0 {
// If no model is available redirect to the index which suggests how to install models // If no model is available redirect to the index which suggests how to install models
return c.Redirect("/") return c.Redirect(utils.BaseURL(c))
} }
summary := fiber.Map{ summary := fiber.Map{
"Title": "LocalAI - Chat with " + backendConfigs[0], "Title": "LocalAI - Chat with " + backendConfigs[0],
"BaseURL": utils.BaseURL(c),
"ModelsConfig": backendConfigs, "ModelsConfig": backendConfigs,
"Model": backendConfigs[0], "Model": backendConfigs[0],
"Version": internal.PrintableVersion(), "Version": internal.PrintableVersion(),
@ -364,6 +370,7 @@ func RegisterUIRoutes(app *fiber.App,
summary := fiber.Map{ summary := fiber.Map{
"Title": "LocalAI - Generate images with " + c.Params("model"), "Title": "LocalAI - Generate images with " + c.Params("model"),
"BaseURL": utils.BaseURL(c),
"ModelsConfig": backendConfigs, "ModelsConfig": backendConfigs,
"Model": c.Params("model"), "Model": c.Params("model"),
"Version": internal.PrintableVersion(), "Version": internal.PrintableVersion(),
@ -380,11 +387,12 @@ func RegisterUIRoutes(app *fiber.App,
if len(backendConfigs) == 0 { if len(backendConfigs) == 0 {
// If no model is available redirect to the index which suggests how to install models // If no model is available redirect to the index which suggests how to install models
return c.Redirect("/") return c.Redirect(utils.BaseURL(c))
} }
summary := fiber.Map{ summary := fiber.Map{
"Title": "LocalAI - Generate images with " + backendConfigs[0].Name, "Title": "LocalAI - Generate images with " + backendConfigs[0].Name,
"BaseURL": utils.BaseURL(c),
"ModelsConfig": backendConfigs, "ModelsConfig": backendConfigs,
"Model": backendConfigs[0].Name, "Model": backendConfigs[0].Name,
"Version": internal.PrintableVersion(), "Version": internal.PrintableVersion(),
@ -400,6 +408,7 @@ func RegisterUIRoutes(app *fiber.App,
summary := fiber.Map{ summary := fiber.Map{
"Title": "LocalAI - Generate images with " + c.Params("model"), "Title": "LocalAI - Generate images with " + c.Params("model"),
"BaseURL": utils.BaseURL(c),
"ModelsConfig": backendConfigs, "ModelsConfig": backendConfigs,
"Model": c.Params("model"), "Model": c.Params("model"),
"Version": internal.PrintableVersion(), "Version": internal.PrintableVersion(),
@ -416,11 +425,12 @@ func RegisterUIRoutes(app *fiber.App,
if len(backendConfigs) == 0 { if len(backendConfigs) == 0 {
// If no model is available redirect to the index which suggests how to install models // If no model is available redirect to the index which suggests how to install models
return c.Redirect("/") return c.Redirect(utils.BaseURL(c))
} }
summary := fiber.Map{ summary := fiber.Map{
"Title": "LocalAI - Generate audio with " + backendConfigs[0].Name, "Title": "LocalAI - Generate audio with " + backendConfigs[0].Name,
"BaseURL": utils.BaseURL(c),
"ModelsConfig": backendConfigs, "ModelsConfig": backendConfigs,
"Model": backendConfigs[0].Name, "Model": backendConfigs[0].Name,
"IsP2PEnabled": p2p.IsP2PEnabled(), "IsP2PEnabled": p2p.IsP2PEnabled(),

View file

@ -7,33 +7,33 @@ https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Roboto:wg
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-display: swap; font-display: swap;
src: url(/static/assets/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfMZg.ttf) format('truetype'); src: url(./UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfMZg.ttf) format('truetype');
} }
@font-face { @font-face {
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
font-display: swap; font-display: swap;
src: url(/static/assets/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuGKYMZg.ttf) format('truetype'); src: url(./UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuGKYMZg.ttf) format('truetype');
} }
@font-face { @font-face {
font-family: 'Inter'; font-family: 'Inter';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
font-display: swap; font-display: swap;
src: url(/static/assets/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuFuYMZg.ttf) format('truetype'); src: url(./UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuFuYMZg.ttf) format('truetype');
} }
@font-face { @font-face {
font-family: 'Roboto'; font-family: 'Roboto';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-display: swap; font-display: swap;
src: url(/static/assets/KFOmCnqEu92Fr1Me5Q.ttf) format('truetype'); src: url(./KFOmCnqEu92Fr1Me5Q.ttf) format('truetype');
} }
@font-face { @font-face {
font-family: 'Roboto'; font-family: 'Roboto';
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
font-display: swap; font-display: swap;
src: url(/static/assets/KFOlCnqEu92Fr1MmEU9vAw.ttf) format('truetype'); src: url(./KFOlCnqEu92Fr1MmEU9vAw.ttf) format('truetype');
} }

View file

@ -7,33 +7,33 @@ https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900&display=swap
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
font-display: swap; font-display: swap;
src: url(/static/assets//KFOlCnqEu92Fr1MmSU5fBBc9.ttf) format('truetype'); src: url(./KFOlCnqEu92Fr1MmSU5fBBc9.ttf) format('truetype');
} }
@font-face { @font-face {
font-family: 'Roboto'; font-family: 'Roboto';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-display: swap; font-display: swap;
src: url(/static/assets//KFOmCnqEu92Fr1Mu4mxP.ttf) format('truetype'); src: url(./KFOmCnqEu92Fr1Mu4mxP.ttf) format('truetype');
} }
@font-face { @font-face {
font-family: 'Roboto'; font-family: 'Roboto';
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
font-display: swap; font-display: swap;
src: url(/static/assets//KFOlCnqEu92Fr1MmEU9fBBc9.ttf) format('truetype'); src: url(./KFOlCnqEu92Fr1MmEU9fBBc9.ttf) format('truetype');
} }
@font-face { @font-face {
font-family: 'Roboto'; font-family: 'Roboto';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
font-display: swap; font-display: swap;
src: url(/static/assets//KFOlCnqEu92Fr1MmWUlfBBc9.ttf) format('truetype'); src: url(./KFOlCnqEu92Fr1MmWUlfBBc9.ttf) format('truetype');
} }
@font-face { @font-face {
font-family: 'Roboto'; font-family: 'Roboto';
font-style: normal; font-style: normal;
font-weight: 900; font-weight: 900;
font-display: swap; font-display: swap;
src: url(/static/assets//KFOlCnqEu92Fr1MmYUtfBBc9.ttf) format('truetype'); src: url(./KFOlCnqEu92Fr1MmYUtfBBc9.ttf) format('truetype');
} }

View file

@ -143,7 +143,7 @@ function readInputImage() {
// } // }
// Source: https://stackoverflow.com/a/75751803/11386095 // Source: https://stackoverflow.com/a/75751803/11386095
const response = await fetch("/v1/chat/completions", { const response = await fetch("v1/chat/completions", {
method: "POST", method: "POST",
headers: { headers: {
Authorization: `Bearer ${key}`, Authorization: `Bearer ${key}`,

View file

@ -48,7 +48,7 @@ async function promptDallE(key, input) {
document.getElementById("input").disabled = true; document.getElementById("input").disabled = true;
const model = document.getElementById("image-model").value; const model = document.getElementById("image-model").value;
const response = await fetch("/v1/images/generations", { const response = await fetch("v1/images/generations", {
method: "POST", method: "POST",
headers: { headers: {
Authorization: `Bearer ${key}`, Authorization: `Bearer ${key}`,

View file

@ -122,7 +122,7 @@ async function sendAudioToWhisper(audioBlob) {
formData.append('model', getWhisperModel()); formData.append('model', getWhisperModel());
API_KEY = localStorage.getItem("key"); API_KEY = localStorage.getItem("key");
const response = await fetch('/v1/audio/transcriptions', { const response = await fetch('v1/audio/transcriptions', {
method: 'POST', method: 'POST',
headers: { headers: {
'Authorization': `Bearer ${API_KEY}` 'Authorization': `Bearer ${API_KEY}`
@ -139,7 +139,7 @@ async function sendTextToChatGPT(text) {
conversationHistory.push({ role: "user", content: text }); conversationHistory.push({ role: "user", content: text });
API_KEY = localStorage.getItem("key"); API_KEY = localStorage.getItem("key");
const response = await fetch('/v1/chat/completions', { const response = await fetch('v1/chat/completions', {
method: 'POST', method: 'POST',
headers: { headers: {
'Authorization': `Bearer ${API_KEY}`, 'Authorization': `Bearer ${API_KEY}`,
@ -163,7 +163,7 @@ async function sendTextToChatGPT(text) {
async function getTextToSpeechAudio(text) { async function getTextToSpeechAudio(text) {
API_KEY = localStorage.getItem("key"); API_KEY = localStorage.getItem("key");
const response = await fetch('/v1/audio/speech', { const response = await fetch('v1/audio/speech', {
method: 'POST', method: 'POST',
headers: { headers: {

View file

@ -19,7 +19,7 @@ async function tts(key, input) {
document.getElementById("input").disabled = true; document.getElementById("input").disabled = true;
const model = document.getElementById("tts-model").value; const model = document.getElementById("tts-model").value;
const response = await fetch("/tts", { const response = await fetch("tts", {
method: "POST", method: "POST",
headers: { headers: {
Authorization: `Bearer ${key}`, Authorization: `Bearer ${key}`,

View file

@ -0,0 +1,24 @@
package utils
import (
"strings"
"github.com/gofiber/fiber/v2"
)
// BaseURL returns the base URL for the given HTTP request context.
// It takes into account that the app may be exposed by a reverse-proxy under a different protocol, host and path.
// The returned URL is guaranteed to end with `/`.
// The method should be used in conjunction with the StripPathPrefix middleware.
func BaseURL(c *fiber.Ctx) string {
path := c.Path()
origPath := c.OriginalURL()
if path != origPath && strings.HasSuffix(origPath, path) {
pathPrefix := origPath[:len(origPath)-len(path)+1]
return c.BaseURL() + pathPrefix
}
return c.BaseURL() + "/"
}

View file

@ -0,0 +1,48 @@
package utils
import (
"net/http/httptest"
"testing"
"github.com/gofiber/fiber/v2"
"github.com/stretchr/testify/require"
)
func TestBaseURL(t *testing.T) {
for _, tc := range []struct {
name string
prefix string
expectURL string
}{
{
name: "without prefix",
prefix: "/",
expectURL: "http://example.com/",
},
{
name: "with prefix",
prefix: "/myprefix/",
expectURL: "http://example.com/myprefix/",
},
} {
t.Run(tc.name, func(t *testing.T) {
app := fiber.New()
actualURL := ""
app.Get(tc.prefix+"hello/world", func(c *fiber.Ctx) error {
if tc.prefix != "/" {
c.Path("/hello/world")
}
actualURL = BaseURL(c)
return nil
})
req := httptest.NewRequest("GET", tc.prefix+"hello/world", nil)
resp, err := app.Test(req, -1)
require.NoError(t, err)
require.Equal(t, 200, resp.StatusCode, "response status code")
require.Equal(t, tc.expectURL, actualURL, "base URL")
})
}
}

View file

@ -12,7 +12,7 @@
<div class="header text-center py-12"> <div class="header text-center py-12">
<h1 class="text-5xl font-bold">Welcome to your LocalAI instance!</h1> <h1 class="text-5xl font-bold">Welcome to your LocalAI instance!</h1>
<div class="mt-6"> <div class="mt-6">
<!-- <a href="/" aria-label="HomePage" alt="HomePage"> <!-- <a href="./" aria-label="HomePage" alt="HomePage">
<img class="mx-auto w-1/4 h-auto" src="https://github.com/go-skynet/LocalAI/assets/2420543/0966aa2a-166e-4f99-a3e5-6c915fc997dd" alt="LocalAI Logo"> <img class="mx-auto w-1/4 h-auto" src="https://github.com/go-skynet/LocalAI/assets/2420543/0966aa2a-166e-4f99-a3e5-6c915fc997dd" alt="LocalAI Logo">
</a> </a>
--> -->

View file

@ -28,7 +28,7 @@ SOFTWARE.
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
{{template "views/partials/head" .}} {{template "views/partials/head" .}}
<script defer src="/static/chat.js"></script> <script defer src="static/chat.js"></script>
<style> <style>
body { body {
overflow: hidden; overflow: hidden;
@ -101,9 +101,9 @@ SOFTWARE.
{{ $model:=.Model}} {{ $model:=.Model}}
{{ range .ModelsConfig }} {{ range .ModelsConfig }}
{{ if eq . $model }} {{ if eq . $model }}
<option value="/chat/{{.}}" selected class="bg-gray-700 text-white">{{.}}</option> <option value="chat/{{.}}" selected class="bg-gray-700 text-white">{{.}}</option>
{{ else }} {{ else }}
<option value="/chat/{{.}}" class="bg-gray-700 text-white">{{.}}</option> <option value="chat/{{.}}" class="bg-gray-700 text-white">{{.}}</option>
{{ end }} {{ end }}
{{ end }} {{ end }}
</select> </select>
@ -142,7 +142,7 @@ SOFTWARE.
<div id="loader" class="my-2 loader" style="display: none;"></div> <div id="loader" class="my-2 loader" style="display: none;"></div>
<input id="chat-model" type="hidden" value="{{.Model}}"> <input id="chat-model" type="hidden" value="{{.Model}}">
<input id="input_image" type="file" style="display: none;" @change="fileName = $event.target.files[0].name"> <input id="input_image" type="file" style="display: none;" @change="fileName = $event.target.files[0].name">
<form id="prompt" action="/chat/{{.Model}}" method="get" @submit.prevent="submitPrompt"> <form id="prompt" action="chat/{{.Model}}" method="get" @submit.prevent="submitPrompt">
<div class="relative w-full"> <div class="relative w-full">
<textarea <textarea
id="input" id="input"

View file

@ -370,7 +370,7 @@
} }
} }
</script> </script>
<script src="/static/p2panimation.js"></script> <script src="static/p2panimation.js"></script>
{{template "views/partials/footer" .}} {{template "views/partials/footer" .}}
</div> </div>

View file

@ -20,7 +20,7 @@
{{template "views/partials/inprogress" .}} {{template "views/partials/inprogress" .}}
{{ if eq (len .ModelsConfig) 0 }} {{ if eq (len .ModelsConfig) 0 }}
<h2 class="text-center text-3xl font-semibold text-gray-100"> <i class="text-yellow-200 ml-2 fa-solid fa-triangle-exclamation animate-pulse"></i> Ouch! seems you don't have any models installed from the LocalAI gallery!</h2> <h2 class="text-center text-3xl font-semibold text-gray-100"> <i class="text-yellow-200 ml-2 fa-solid fa-triangle-exclamation animate-pulse"></i> Ouch! seems you don't have any models installed from the LocalAI gallery!</h2>
<p class="text-center mt-4 text-xl">..install something from the <a class="text-gray-400 hover:text-white ml-1 px-3 py-2 rounded" href="/browse">🖼️ Gallery</a> or check the <a href="https://localai.io/basics/getting_started/" class="text-gray-400 hover:text-white ml-1 px-3 py-2 rounded"> <i class="fa-solid fa-book"></i> Getting started documentation </a></p> <p class="text-center mt-4 text-xl">..install something from the <a class="text-gray-400 hover:text-white ml-1 px-3 py-2 rounded" href="browse">🖼️ Gallery</a> or check the <a href="https://localai.io/basics/getting_started/" class="text-gray-400 hover:text-white ml-1 px-3 py-2 rounded"> <i class="fa-solid fa-book"></i> Getting started documentation </a></p>
{{ if ne (len .Models) 0 }} {{ if ne (len .Models) 0 }}
<hr class="my-4"> <hr class="my-4">
@ -66,7 +66,7 @@
{{ end }} {{ end }}
</td> </td>
<td class="px-4 py-3 font-bold"> <td class="px-4 py-3 font-bold">
<p class="font-bold text-white flex items-center"><i class="fas fa-brain pr-2"></i><a href="/browse?term={{.Name}}">{{.Name}}</a></p> <p class="font-bold text-white flex items-center"><i class="fas fa-brain pr-2"></i><a href="browse?term={{.Name}}">{{.Name}}</a></p>
</td> </td>
<td class="px-4 py-3 font-bold"> <td class="px-4 py-3 font-bold">
{{ if .Backend }} {{ if .Backend }}
@ -84,7 +84,7 @@
<td class="px-4 py-3"> <td class="px-4 py-3">
<button <button
class="float-right inline-block rounded bg-red-800 px-6 pb-2.5 mb-3 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-red-accent-300 hover:shadow-red-2 focus:bg-red-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-red-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong" class="float-right inline-block rounded bg-red-800 px-6 pb-2.5 mb-3 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-red-accent-300 hover:shadow-red-2 focus:bg-red-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-red-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-ripple-color="light" data-twe-ripple-init="" hx-confirm="Are you sure you wish to delete the model?" hx-post="/browse/delete/model/{{.Name}}" hx-swap="outerHTML"><i class="fa-solid fa-cancel pr-2"></i>Delete</button> data-twe-ripple-color="light" data-twe-ripple-init="" hx-confirm="Are you sure you wish to delete the model?" hx-post="browse/delete/model/{{.Name}}" hx-swap="outerHTML"><i class="fa-solid fa-cancel pr-2"></i>Delete</button>
</td> </td>
{{ end }} {{ end }}
{{ range .Models }} {{ range .Models }}

View file

@ -4,6 +4,8 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Open Authenticated Website</title> <title>Open Authenticated Website</title>
<base href="{{.BaseURL}}" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head> </head>
<body> <body>
<h1>Authorization is required</h1> <h1>Authorization is required</h1>

View file

@ -16,38 +16,38 @@
<div class="text-center font-semibold text-gray-100"> <div class="text-center font-semibold text-gray-100">
<h2>Filter by type:</h2> <h2>Filter by type:</h2>
<button hx-post="/browse/search/models" <button hx-post="browse/search/models"
class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2" class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2"
hx-target="#search-results" hx-target="#search-results"
hx-vals='{"search": "tts"}' hx-vals='{"search": "tts"}'
hx-indicator=".htmx-indicator" >TTS</button> hx-indicator=".htmx-indicator" >TTS</button>
<button hx-post="/browse/search/models" <button hx-post="browse/search/models"
class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2" class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2"
hx-target="#search-results" hx-target="#search-results"
hx-vals='{"search": "stablediffusion"}' hx-vals='{"search": "stablediffusion"}'
hx-indicator=".htmx-indicator" >Image generation</button> hx-indicator=".htmx-indicator" >Image generation</button>
<button hx-post="/browse/search/models" \ <button hx-post="browse/search/models" \
class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2" class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2"
hx-target="#search-results" hx-target="#search-results"
hx-vals='{"search": "llm"}' hx-vals='{"search": "llm"}'
hx-indicator=".htmx-indicator" >Text generation</button> hx-indicator=".htmx-indicator" >Text generation</button>
<button hx-post="/browse/search/models" <button hx-post="browse/search/models"
class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2" class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2"
hx-target="#search-results" hx-target="#search-results"
hx-vals='{"search": "multimodal"}' hx-vals='{"search": "multimodal"}'
hx-indicator=".htmx-indicator" >Multimodal</button> hx-indicator=".htmx-indicator" >Multimodal</button>
<button hx-post="/browse/search/models" <button hx-post="browse/search/models"
class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2" class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2"
hx-target="#search-results" hx-target="#search-results"
hx-vals='{"search": "embedding"}' hx-vals='{"search": "embedding"}'
hx-indicator=".htmx-indicator" >Embeddings</button> hx-indicator=".htmx-indicator" >Embeddings</button>
<button hx-post="/browse/search/models" <button hx-post="browse/search/models"
class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2" class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2"
hx-target="#search-results" hx-target="#search-results"
hx-vals='{"search": "rerank"}' hx-vals='{"search": "rerank"}'
hx-indicator=".htmx-indicator" >Rerankers</button> hx-indicator=".htmx-indicator" >Rerankers</button>
<button <button
hx-post="/browse/search/models" hx-post="browse/search/models"
class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2" class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2"
hx-target="#search-results" hx-target="#search-results"
hx-vals='{"search": "whisper"}' hx-vals='{"search": "whisper"}'
@ -57,7 +57,7 @@
<div class="text-center text-xs font-semibold text-gray-100"> <div class="text-center text-xs font-semibold text-gray-100">
Filter by tags: Filter by tags:
{{ range .AllTags }} {{ range .AllTags }}
<button hx-post="/browse/search/models" class="text-blue-500" hx-target="#search-results" <button hx-post="browse/search/models" class="text-blue-500" hx-target="#search-results"
hx-vals='{"search": "{{.}}"}' hx-vals='{"search": "{{.}}"}'
hx-indicator=".htmx-indicator" >{{.}}</button> hx-indicator=".htmx-indicator" >{{.}}</button>
{{ end }} {{ end }}
@ -69,7 +69,7 @@
<input class="form-control appearance-none block w-full mt-5 px-3 py-2 text-base font-normal text-gray-300 pb-2 mb-5 bg-gray-800 bg-clip-padding border border-solid border-gray-600 rounded transition ease-in-out m-0 focus:text-gray-300 focus:bg-gray-900 focus:border-blue-500 focus:outline-none" type="search" <input class="form-control appearance-none block w-full mt-5 px-3 py-2 text-base font-normal text-gray-300 pb-2 mb-5 bg-gray-800 bg-clip-padding border border-solid border-gray-600 rounded transition ease-in-out m-0 focus:text-gray-300 focus:bg-gray-900 focus:border-blue-500 focus:outline-none" type="search"
name="search" placeholder="Begin Typing To Search models..." name="search" placeholder="Begin Typing To Search models..."
hx-post="/browse/search/models" hx-post="browse/search/models"
hx-trigger="input changed delay:500ms, search" hx-trigger="input changed delay:500ms, search"
hx-target="#search-results" hx-target="#search-results"
hx-indicator=".htmx-indicator"> hx-indicator=".htmx-indicator">

View file

@ -48,11 +48,11 @@
<!-- Federation Box --> <!-- Federation Box -->
<div class="bg-gray-800 p-6 rounded-lg shadow-lg mb-12 text-left"> <div class="bg-gray-800 p-6 rounded-lg shadow-lg mb-12 text-left">
<p class="text-xl font-semibold text-gray-200"> <i class="text-gray-200 fa-solid fa-circle-nodes"></i> Federated Nodes: <span hx-get="/p2p/ui/workers-federation-stats" hx-trigger="every 1s"></span> </p> <p class="text-xl font-semibold text-gray-200"> <i class="text-gray-200 fa-solid fa-circle-nodes"></i> Federated Nodes: <span hx-get="p2p/ui/workers-federation-stats" hx-trigger="every 1s"></span> </p>
<p class="mb-4">You can start LocalAI in federated mode to share your instance, or start the federated server to balance requests between nodes of the federation.</p> <p class="mb-4">You can start LocalAI in federated mode to share your instance, or start the federated server to balance requests between nodes of the federation.</p>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 mb-12"> <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 mb-12">
<div hx-get="/p2p/ui/workers-federation" hx-trigger="every 1s"></div> <div hx-get="p2p/ui/workers-federation" hx-trigger="every 1s"></div>
</div> </div>
<hr class="border-gray-700 mb-12"> <hr class="border-gray-700 mb-12">
@ -123,11 +123,11 @@
<div class="bg-gray-800 p-6 rounded-lg shadow-lg mb-12 text-left"> <div class="bg-gray-800 p-6 rounded-lg shadow-lg mb-12 text-left">
<p class="text-xl font-semibold text-gray-200"> <i class="text-gray-200 fa-solid fa-circle-nodes"></i> Workers (llama.cpp): <span hx-get="/p2p/ui/workers-stats" hx-trigger="every 1s"></span> </p> <p class="text-xl font-semibold text-gray-200"> <i class="text-gray-200 fa-solid fa-circle-nodes"></i> Workers (llama.cpp): <span hx-get="p2p/ui/workers-stats" hx-trigger="every 1s"></span> </p>
<p class="mb-4">You can start llama.cpp workers to distribute weights between the workers and offload part of the computation. To start a new worker, you can use the CLI or Docker.</p> <p class="mb-4">You can start llama.cpp workers to distribute weights between the workers and offload part of the computation. To start a new worker, you can use the CLI or Docker.</p>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 mb-12"> <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 mb-12">
<div hx-get="/p2p/ui/workers" hx-trigger="every 1s"></div> <div hx-get="p2p/ui/workers" hx-trigger="every 1s"></div>
</div> </div>
<hr class="border-gray-700 mb-12"> <hr class="border-gray-700 mb-12">
@ -177,7 +177,7 @@
{{template "views/partials/footer" .}} {{template "views/partials/footer" .}}
</div> </div>
<script src="/static/p2panimation.js"></script> <script src="static/p2panimation.js"></script>
<style> <style>
.token { .token {
word-break: break-all; word-break: break-all;

View file

@ -2,4 +2,4 @@
LocalAI Version {{.Version}}<br> LocalAI Version {{.Version}}<br>
<a href='https://github.com/mudler/LocalAI' class="text-blue-400 hover:text-blue-600" target="_blank">LocalAI</a> © 2023-2024 <a href='https://mudler.pm' class="text-blue-400 hover:text-blue-600" target="_blank">Ettore Di Giacinto</a> <a href='https://github.com/mudler/LocalAI' class="text-blue-400 hover:text-blue-600" target="_blank">LocalAI</a> © 2023-2024 <a href='https://mudler.pm' class="text-blue-400 hover:text-blue-600" target="_blank">Ettore Di Giacinto</a>
</footer> </footer>
<script src="/static/assets/tw-elements.js"></script> <script src="static/assets/tw-elements.js"></script>

View file

@ -2,33 +2,35 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{.Title}}</title> <title>{{.Title}}</title>
<base href="{{.BaseURL}}" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<link <link
rel="stylesheet" rel="stylesheet"
href="/static/assets/highlightjs.css" href="static/assets/highlightjs.css"
/> />
<script defer src="/static/assets/highlightjs.js"></script> <script defer src="static/assets/highlightjs.js"></script>
<script <script
defer defer
src="/static/assets/alpine.js" src="static/assets/alpine.js"
></script> ></script>
<script <script
defer defer
src="/static/assets/marked.js" src="static/assets/marked.js"
></script> ></script>
<script <script
defer defer
src="/static/assets/purify.js" src="static/assets/purify.js"
></script> ></script>
<link href="/static/general.css" rel="stylesheet" /> <link href="static/general.css" rel="stylesheet" />
<link href="/static/assets/font1.css" rel="stylesheet"> <link href="static/assets/font1.css" rel="stylesheet">
<link <link
href="/static/assets/font2.css" href="static/assets/font2.css"
rel="stylesheet" /> rel="stylesheet" />
<link <link
rel="stylesheet" rel="stylesheet"
href="/static/assets/tw-elements.css" /> href="static/assets/tw-elements.css" />
<script src="/static/assets/tailwindcss.js"></script> <script src="static/assets/tailwindcss.js"></script>
<script> <script>
tailwind.config = { tailwind.config = {
darkMode: "class", darkMode: "class",
@ -54,11 +56,11 @@
}); });
} }
</script> </script>
<link href="/static/assets/fontawesome/css/fontawesome.css" rel="stylesheet" /> <link href="static/assets/fontawesome/css/fontawesome.css" rel="stylesheet" />
<link href="/static/assets/fontawesome/css/brands.css" rel="stylesheet" /> <link href="static/assets/fontawesome/css/brands.css" rel="stylesheet" />
<link href="/static/assets/fontawesome/css/solid.css" rel="stylesheet" /> <link href="static/assets/fontawesome/css/solid.css" rel="stylesheet" />
<script src="/static/assets/flowbite.min.js"></script> <script src="static/assets/flowbite.min.js"></script>
<script src="/static/assets/htmx.js" crossorigin="anonymous"></script> <script src="static/assets/htmx.js" crossorigin="anonymous"></script>
<!-- P2P Animation START --> <!-- P2P Animation START -->
<style> <style>
.animation-container { .animation-container {

View file

@ -17,13 +17,13 @@
<div class="flex items-center justify-between bg-slate-600 p-2 mb-2 rounded-md"> <div class="flex items-center justify-between bg-slate-600 p-2 mb-2 rounded-md">
<div class="flex items center"> <div class="flex items center">
<span class="text-gray-300"><a href="/browse?term={{$parts._1}}" <span class="text-gray-300"><a href="browse?term={{$parts._1}}"
class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2" class="text-white-500 inline-block bg-blue-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2 hover:bg-gray-300 hover:shadow-gray-2"
>{{$modelName}}</a> {{if $repository}} (from the '{{$repository}}' repository) {{end}}</span> >{{$modelName}}</a> {{if $repository}} (from the '{{$repository}}' repository) {{end}}</span>
</div> </div>
<div hx-get="/browse/job/{{$value}}" hx-swap="outerHTML" hx-target="this" hx-trigger="done"> <div hx-get="browse/job/{{$value}}" hx-swap="outerHTML" hx-target="this" hx-trigger="done">
<h3 role="status" id="pblabel" >{{$op}} <h3 role="status" id="pblabel" >{{$op}}
<div hx-get="/browse/job/progress/{{$value}}" hx-trigger="every 600ms" <div hx-get="browse/job/progress/{{$value}}" hx-trigger="every 600ms"
hx-target="this" hx-target="this"
hx-swap="innerHTML" ></div></h3> hx-swap="innerHTML" ></div></h3>
</div> </div>

View file

@ -3,8 +3,8 @@
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div class="flex items-center"> <div class="flex items-center">
<!-- Logo Image: Replace 'logo_url_here' with your actual logo URL --> <!-- Logo Image: Replace 'logo_url_here' with your actual logo URL -->
<a href="/" class="text-white text-xl font-bold"><img src="https://github.com/go-skynet/LocalAI/assets/2420543/0966aa2a-166e-4f99-a3e5-6c915fc997dd" alt="LocalAI Logo" class="h-10 mr-3 border-2 border-gray-300 shadow rounded"></a> <a href="./" class="text-white text-xl font-bold"><img src="https://github.com/go-skynet/LocalAI/assets/2420543/0966aa2a-166e-4f99-a3e5-6c915fc997dd" alt="LocalAI Logo" class="h-10 mr-3 border-2 border-gray-300 shadow rounded"></a>
<a href="/" class="text-white text-xl font-bold">LocalAI</a> <a href="./" class="text-white text-xl font-bold">LocalAI</a>
</div> </div>
<!-- Menu button for small screens --> <!-- Menu button for small screens -->
<div class="lg:hidden"> <div class="lg:hidden">
@ -14,33 +14,33 @@
</div> </div>
<!-- Navigation links --> <!-- Navigation links -->
<div class="hidden lg:flex lg:items-center lg:justify-end lg:flex-1 lg:w-0"> <div class="hidden lg:flex lg:items-center lg:justify-end lg:flex-1 lg:w-0">
<a href="/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-home pr-2"></i>Home</a> <a href="./" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-home pr-2"></i>Home</a>
<a href="https://localai.io" class="text-gray-400 hover:text-white px-3 py-2 rounded" target="_blank" ><i class="fas fa-book-reader pr-2"></i> Documentation</a> <a href="https://localai.io" class="text-gray-400 hover:text-white px-3 py-2 rounded" target="_blank" ><i class="fas fa-book-reader pr-2"></i> Documentation</a>
<a href="/browse/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-brain pr-2"></i> Models</a> <a href="browse/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-brain pr-2"></i> Models</a>
<a href="/chat/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fa-solid fa-comments pr-2"></i> Chat</a> <a href="chat/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fa-solid fa-comments pr-2"></i> Chat</a>
<a href="/text2image/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-image pr-2"></i> Generate images</a> <a href="text2image/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-image pr-2"></i> Generate images</a>
<a href="/tts/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fa-solid fa-music pr-2"></i> TTS </a> <a href="tts/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fa-solid fa-music pr-2"></i> TTS </a>
<a href="/talk/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fa-solid fa-phone pr-2"></i> Talk </a> <a href="talk/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fa-solid fa-phone pr-2"></i> Talk </a>
{{ if .IsP2PEnabled }} {{ if .IsP2PEnabled }}
<a href="/p2p/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fa-solid fa-circle-nodes"></i> Swarm </a> <a href="p2p/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fa-solid fa-circle-nodes"></i> Swarm </a>
{{ end }} {{ end }}
<a href="/swagger/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-code pr-2"></i> API</a> <a href="swagger/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-code pr-2"></i> API</a>
</div> </div>
</div> </div>
<!-- Collapsible menu for small screens --> <!-- Collapsible menu for small screens -->
<div class="hidden lg:hidden" id="mobile-menu"> <div class="hidden lg:hidden" id="mobile-menu">
<div class="pt-4 pb-3 border-t border-gray-700"> <div class="pt-4 pb-3 border-t border-gray-700">
<a href="/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fas fa-home pr-2"></i>Home</a> <a href="./" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fas fa-home pr-2"></i>Home</a>
<a href="https://localai.io" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1" target="_blank" ><i class="fas fa-book-reader pr-2"></i> Documentation</a> <a href="https://localai.io" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1" target="_blank" ><i class="fas fa-book-reader pr-2"></i> Documentation</a>
<a href="/browse/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fas fa-brain pr-2"></i> Models</a> <a href="browse/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fas fa-brain pr-2"></i> Models</a>
<a href="/chat/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fa-solid fa-comments pr-2"></i> Chat</a> <a href="chat/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fa-solid fa-comments pr-2"></i> Chat</a>
<a href="/text2image/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fas fa-image pr-2"></i> Generate images</a> <a href="text2image/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fas fa-image pr-2"></i> Generate images</a>
<a href="/tts/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fa-solid fa-music pr-2"></i> TTS </a> <a href="tts/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fa-solid fa-music pr-2"></i> TTS </a>
<a href="/talk/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fa-solid fa-phone pr-2"></i> Talk </a> <a href="talk/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fa-solid fa-phone pr-2"></i> Talk </a>
{{ if .IsP2PEnabled }} {{ if .IsP2PEnabled }}
<a href="/p2p/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fa-solid fa-circle-nodes"></i> Swarm </a> <a href="p2p/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fa-solid fa-circle-nodes"></i> Swarm </a>
{{ end }} {{ end }}
<a href="/swagger/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fas fa-code pr-2"></i> API</a> <a href="swagger/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fas fa-code pr-2"></i> API</a>
</div> </div>
</div> </div>
</div> </div>

View file

@ -3,8 +3,8 @@
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div class="flex items-center"> <div class="flex items-center">
<!-- Logo Image: Replace 'logo_url_here' with your actual logo URL --> <!-- Logo Image: Replace 'logo_url_here' with your actual logo URL -->
<a href="/" class="text-white text-xl font-bold"><img src="https://github.com/go-skynet/LocalAI/assets/2420543/0966aa2a-166e-4f99-a3e5-6c915fc997dd" alt="LocalAI Logo" class="h-10 mr-3 border-2 border-gray-300 shadow rounded"></a> <a href="./" class="text-white text-xl font-bold"><img src="https://github.com/go-skynet/LocalAI/assets/2420543/0966aa2a-166e-4f99-a3e5-6c915fc997dd" alt="LocalAI Logo" class="h-10 mr-3 border-2 border-gray-300 shadow rounded"></a>
<a href="/" class="text-white text-xl font-bold">LocalAI</a> <a href="./" class="text-white text-xl font-bold">LocalAI</a>
</div> </div>
<!-- Menu button for small screens --> <!-- Menu button for small screens -->
<div class="lg:hidden"> <div class="lg:hidden">
@ -14,7 +14,7 @@
</div> </div>
<!-- Navigation links --> <!-- Navigation links -->
<div class="hidden lg:flex lg:items-center lg:justify-end lg:flex-1 lg:w-0"> <div class="hidden lg:flex lg:items-center lg:justify-end lg:flex-1 lg:w-0">
<a href="/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-home pr-2"></i>Home</a> <a href="./" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-home pr-2"></i>Home</a>
<a href="https://localai.io" class="text-gray-400 hover:text-white px-3 py-2 rounded" target="_blank" ><i class="fas fa-book-reader pr-2"></i> Documentation</a> <a href="https://localai.io" class="text-gray-400 hover:text-white px-3 py-2 rounded" target="_blank" ><i class="fas fa-book-reader pr-2"></i> Documentation</a>
<a href="https://models.localai.io/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-brain pr-2"></i> Models</a> <a href="https://models.localai.io/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-brain pr-2"></i> Models</a>
</div> </div>
@ -22,7 +22,7 @@
<!-- Collapsible menu for small screens --> <!-- Collapsible menu for small screens -->
<div class="hidden lg:hidden" id="mobile-menu"> <div class="hidden lg:hidden" id="mobile-menu">
<div class="pt-4 pb-3 border-t border-gray-700"> <div class="pt-4 pb-3 border-t border-gray-700">
<a href="/" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fas fa-home pr-2"></i>Home</a> <a href="./" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1"><i class="fas fa-home pr-2"></i>Home</a>
<a href="https://localai.io" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1" target="_blank" ><i class="fas fa-book-reader pr-2"></i> Documentation</a> <a href="https://localai.io" class="block text-gray-400 hover:text-white px-3 py-2 rounded mt-1" target="_blank" ><i class="fas fa-book-reader pr-2"></i> Documentation</a>
<a href="https://models.localai.io/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-brain pr-2"></i> Models</a> <a href="https://models.localai.io/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-brain pr-2"></i> Models</a>
</div> </div>

View file

@ -1,7 +1,7 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
{{template "views/partials/head" .}} {{template "views/partials/head" .}}
<script defer src="/static/talk.js"></script> <script defer src="static/talk.js"></script>
<style> <style>
body { body {
overflow: hidden; overflow: hidden;

View file

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
{{template "views/partials/head" .}} {{template "views/partials/head" .}}
<script defer src="/static/image.js"></script> <script defer src="static/image.js"></script>
<body class="bg-gray-900 text-gray-200"> <body class="bg-gray-900 text-gray-200">
<div class="flex flex-col min-h-screen"> <div class="flex flex-col min-h-screen">
@ -50,9 +50,9 @@
{{ $model:=.Model}} {{ $model:=.Model}}
{{ range .ModelsConfig }} {{ range .ModelsConfig }}
{{ if eq .Name $model }} {{ if eq .Name $model }}
<option value="/text2image/{{.Name}}" selected class="bg-gray-700 text-white">{{.Name}}</option> <option value="text2image/{{.Name}}" selected class="bg-gray-700 text-white">{{.Name}}</option>
{{ else }} {{ else }}
<option value="/text2image/{{.Name}}" class="bg-gray-700 text-white">{{.Name}}</option> <option value="text2image/{{.Name}}" class="bg-gray-700 text-white">{{.Name}}</option>
{{ end }} {{ end }}
{{ end }} {{ end }}
</select> </select>
@ -62,7 +62,7 @@
<div class="mt-12"> <div class="mt-12">
<input id="image-model" type="hidden" value="{{.Model}}"> <input id="image-model" type="hidden" value="{{.Model}}">
<form id="genimage" action="/text2image/{{.Model}}" method="get"> <form id="genimage" action="text2image/{{.Model}}" method="get">
<input <input
type="text" type="text"
id="input" id="input"

View file

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
{{template "views/partials/head" .}} {{template "views/partials/head" .}}
<script defer src="/static/tts.js"></script> <script defer src="static/tts.js"></script>
<body class="bg-gray-900 text-gray-200"> <body class="bg-gray-900 text-gray-200">
<div class="flex flex-col min-h-screen"> <div class="flex flex-col min-h-screen">
@ -47,9 +47,9 @@
{{ $model:=.Model}} {{ $model:=.Model}}
{{ range .ModelsConfig }} {{ range .ModelsConfig }}
{{ if eq .Name $model }} {{ if eq .Name $model }}
<option value="/tts/{{.Name}}" selected class="bg-gray-700 text-white">{{.Name}}</option> <option value="tts/{{.Name}}" selected class="bg-gray-700 text-white">{{.Name}}</option>
{{ else }} {{ else }}
<option value="/tts/{{.Name}}" class="bg-gray-700 text-white">{{.Name}}</option> <option value="tts/{{.Name}}" class="bg-gray-700 text-white">{{.Name}}</option>
{{ end }} {{ end }}
{{ end }} {{ end }}
</select> </select>
@ -59,7 +59,7 @@
<div class="mt-12"> <div class="mt-12">
<input id="tts-model" type="hidden" value="{{.Model}}"> <input id="tts-model" type="hidden" value="{{.Model}}">
<form id="tts" action="/tts/{{.Model}}" method="get"> <form id="tts" action="tts/{{.Model}}" method="get">
<input <input
type="text" type="text"
id="input" id="input"

View file

@ -16,8 +16,8 @@ LocalAI will attempt to automatically load models which are not explicitly confi
| Backend and Bindings | Compatible models | Completion/Chat endpoint | Capability | Embeddings support | Token stream support | Acceleration | | Backend and Bindings | Compatible models | Completion/Chat endpoint | Capability | Embeddings support | Token stream support | Acceleration |
|----------------------------------------------------------------------------------|-----------------------|--------------------------|---------------------------|-----------------------------------|----------------------|--------------| |----------------------------------------------------------------------------------|-----------------------|--------------------------|---------------------------|-----------------------------------|----------------------|--------------|
| [llama.cpp]({{%relref "docs/features/text-generation#llama.cpp" %}}) | LLama, Mamba, RWKV, Falcon, Starcoder, GPT-2, [and many others](https://github.com/ggerganov/llama.cpp?tab=readme-ov-file#description) | yes | GPT and Functions | yes** | yes | CUDA, openCL, cuBLAS, Metal | | [llama.cpp]({{%relref "docs/features/text-generation#llama.cpp" %}}) | LLama, Mamba, RWKV, Falcon, Starcoder, GPT-2, [and many others](https://github.com/ggerganov/llama.cpp?tab=readme-ov-file#description) | yes | GPT and Functions | yes | yes | CUDA, openCL, cuBLAS, Metal |
| [llama.cpp's ggml model (backward compatibility with old format, before GGUF)](https://github.com/ggerganov/llama.cpp) ([binding](https://github.com/go-skynet/go-llama.cpp)) | LLama, GPT-2, [and many others](https://github.com/ggerganov/llama.cpp?tab=readme-ov-file#description) | yes | GPT and Functions | yes** | yes | CUDA, openCL, cuBLAS, Metal | | [llama.cpp's ggml model (backward compatibility with old format, before GGUF)](https://github.com/ggerganov/llama.cpp) ([binding](https://github.com/go-skynet/go-llama.cpp)) | LLama, GPT-2, [and many others](https://github.com/ggerganov/llama.cpp?tab=readme-ov-file#description) | yes | GPT and Functions | yes | yes | CUDA, openCL, cuBLAS, Metal |
| [whisper](https://github.com/ggerganov/whisper.cpp) | whisper | no | Audio | no | no | N/A | | [whisper](https://github.com/ggerganov/whisper.cpp) | whisper | no | Audio | no | no | N/A |
| [stablediffusion](https://github.com/EdVince/Stable-Diffusion-NCNN) ([binding](https://github.com/mudler/go-stable-diffusion)) | stablediffusion | no | Image | no | no | N/A | | [stablediffusion](https://github.com/EdVince/Stable-Diffusion-NCNN) ([binding](https://github.com/mudler/go-stable-diffusion)) | stablediffusion | no | Image | no | no | N/A |
| [langchain-huggingface](https://github.com/tmc/langchaingo) | Any text generators available on HuggingFace through API | yes | GPT | no | no | N/A | | [langchain-huggingface](https://github.com/tmc/langchaingo) | Any text generators available on HuggingFace through API | yes | GPT | no | no | N/A |
@ -37,14 +37,11 @@ LocalAI will attempt to automatically load models which are not explicitly confi
| `openvoice` | Open voice | no | Audio generation and Voice cloning | no | no | CPU/CUDA | | `openvoice` | Open voice | no | Audio generation and Voice cloning | no | no | CPU/CUDA |
| `parler-tts` | Open voice | no | Audio generation and Voice cloning | no | no | CPU/CUDA | | `parler-tts` | Open voice | no | Audio generation and Voice cloning | no | no | CPU/CUDA |
| [rerankers](https://github.com/AnswerDotAI/rerankers) | Reranking API | no | Reranking | no | no | CPU/CUDA | | [rerankers](https://github.com/AnswerDotAI/rerankers) | Reranking API | no | Reranking | no | no | CPU/CUDA |
| `transformers` | Various GPTs and quantization formats | yes | GPT, embeddings | yes | yes**** | CPU/CUDA/XPU | | `transformers` | Various GPTs and quantization formats | yes | GPT, embeddings | yes | yes* | CPU/CUDA/XPU |
| [bark-cpp](https://github.com/PABannier/bark.cpp) | bark | no | Audio-Only | no | no | yes | | [bark-cpp](https://github.com/PABannier/bark.cpp) | bark | no | Audio-Only | no | no | yes |
| [stablediffusion-cpp](https://github.com/leejet/stable-diffusion.cpp) | stablediffusion-1, stablediffusion-2, stablediffusion-3, flux, PhotoMaker | no | Image | no | no | N/A | | [stablediffusion-cpp](https://github.com/leejet/stable-diffusion.cpp) | stablediffusion-1, stablediffusion-2, stablediffusion-3, flux, PhotoMaker | no | Image | no | no | N/A |
| [silero-vad](https://github.com/snakers4/silero-vad) with [Golang bindings](https://github.com/streamer45/silero-vad-go) | Silero VAD | no | Voice Activity Detection | no | no | CPU | | [silero-vad](https://github.com/snakers4/silero-vad) with [Golang bindings](https://github.com/streamer45/silero-vad-go) | Silero VAD | no | Voice Activity Detection | no | no | CPU |
Note: any backend name listed above can be used in the `backend` field of the model configuration file (See [the advanced section]({{%relref "docs/advanced" %}})). Note: any backend name listed above can be used in the `backend` field of the model configuration file (See [the advanced section]({{%relref "docs/advanced" %}})).
- \* 7b ONLY - \* Only for CUDA and OpenVINO CPU/XPU acceleration.
- ** doesn't seem to be accurate
- *** 7b and 40b with the `ggccv` format, for instance: https://huggingface.co/TheBloke/WizardLM-Uncensored-Falcon-40B-GGML
- **** Only for CUDA and OpenVINO CPU/XPU acceleration.

@ -1 +1 @@
Subproject commit d25f856477223170b0de0b284252aa54b3e6255b Subproject commit 80e448e5bdaa92c87ee0d0d86f1125c8606ebf5f

View file

@ -1069,6 +1069,56 @@
- filename: Llama-Deepsync-3B.Q4_K_M.gguf - filename: Llama-Deepsync-3B.Q4_K_M.gguf
sha256: f11c4d9b10a732845d8e64dc9badfcbb7d94053bc5fe11f89bb8e99ed557f711 sha256: f11c4d9b10a732845d8e64dc9badfcbb7d94053bc5fe11f89bb8e99ed557f711
uri: huggingface://prithivMLmods/Llama-Deepsync-3B-GGUF/Llama-Deepsync-3B.Q4_K_M.gguf uri: huggingface://prithivMLmods/Llama-Deepsync-3B-GGUF/Llama-Deepsync-3B.Q4_K_M.gguf
- !!merge <<: *llama32
name: "dolphin3.0-llama3.2-1b"
url: "github:mudler/LocalAI/gallery/chatml.yaml@master"
icon: https://cdn-uploads.huggingface.co/production/uploads/63111b2d88942700629f5771/cNCs1TBD3FelWCJGkZ3cd.png
urls:
- https://huggingface.co/cognitivecomputations/Dolphin3.0-Llama3.2-1B
- https://huggingface.co/bartowski/Dolphin3.0-Llama3.2-1B-GGUF
description: |
Dolphin 3.0 is the next generation of the Dolphin series of instruct-tuned models. Designed to be the ultimate general purpose local model, enabling coding, math, agentic, function calling, and general use cases.
Dolphin aims to be a general purpose model, similar to the models behind ChatGPT, Claude, Gemini. But these models present problems for businesses seeking to include AI in their products.
They maintain control of the system prompt, deprecating and changing things as they wish, often causing software to break.
They maintain control of the model versions, sometimes changing things silently, or deprecating older models that your business relies on.
They maintain control of the alignment, and in particular the alignment is one-size-fits all, not tailored to the application.
They can see all your queries and they can potentially use that data in ways you wouldn't want. Dolphin, in contrast, is steerable and gives control to the system owner. You set the system prompt. You decide the alignment. You have control of your data. Dolphin does not impose its ethics or guidelines on you. You are the one who decides the guidelines.
Dolphin belongs to YOU, it is your tool, an extension of your will. Just as you are personally responsible for what you do with a knife, gun, fire, car, or the internet, you are the creator and originator of any content you generate with Dolphin.
overrides:
parameters:
model: Dolphin3.0-Llama3.2-1B-Q4_K_M.gguf
files:
- filename: Dolphin3.0-Llama3.2-1B-Q4_K_M.gguf
sha256: 7ed39ee0638e18d3e47bf12e60e917c792ca5332606a72bd1882ab1f62a13a7a
uri: huggingface://bartowski/Dolphin3.0-Llama3.2-1B-GGUF/Dolphin3.0-Llama3.2-1B-Q4_K_M.gguf
- !!merge <<: *llama32
name: "dolphin3.0-llama3.2-3b"
icon: https://cdn-uploads.huggingface.co/production/uploads/63111b2d88942700629f5771/cNCs1TBD3FelWCJGkZ3cd.png
url: "github:mudler/LocalAI/gallery/chatml.yaml@master"
urls:
- https://huggingface.co/cognitivecomputations/Dolphin3.0-Llama3.2-3B
- https://huggingface.co/bartowski/Dolphin3.0-Llama3.2-3B-GGUF
description: |
Dolphin 3.0 is the next generation of the Dolphin series of instruct-tuned models. Designed to be the ultimate general purpose local model, enabling coding, math, agentic, function calling, and general use cases.
Dolphin aims to be a general purpose model, similar to the models behind ChatGPT, Claude, Gemini. But these models present problems for businesses seeking to include AI in their products.
They maintain control of the system prompt, deprecating and changing things as they wish, often causing software to break.
They maintain control of the model versions, sometimes changing things silently, or deprecating older models that your business relies on.
They maintain control of the alignment, and in particular the alignment is one-size-fits all, not tailored to the application.
They can see all your queries and they can potentially use that data in ways you wouldn't want. Dolphin, in contrast, is steerable and gives control to the system owner. You set the system prompt. You decide the alignment. You have control of your data. Dolphin does not impose its ethics or guidelines on you. You are the one who decides the guidelines.
Dolphin belongs to YOU, it is your tool, an extension of your will. Just as you are personally responsible for what you do with a knife, gun, fire, car, or the internet, you are the creator and originator of any content you generate with Dolphin.
overrides:
parameters:
model: Dolphin3.0-Llama3.2-3B-Q4_K_M.gguf
files:
- filename: Dolphin3.0-Llama3.2-3B-Q4_K_M.gguf
sha256: 5d6d02eeefa1ab5dbf23f97afdf5c2c95ad3d946dc3b6e9ab72e6c1637d54177
uri: huggingface://bartowski/Dolphin3.0-Llama3.2-3B-GGUF/Dolphin3.0-Llama3.2-3B-Q4_K_M.gguf
- &qwen25 - &qwen25
## Qwen2.5 ## Qwen2.5
name: "qwen2.5-14b-instruct" name: "qwen2.5-14b-instruct"
@ -2662,6 +2712,119 @@
- filename: lwd-Mirau-RP-Q4_K_M-imat.gguf - filename: lwd-Mirau-RP-Q4_K_M-imat.gguf
sha256: 22ff461e9034b9ebded07b2a9d3d88c2f75359d5c069ebb3ee4e9c6ec5c45cf8 sha256: 22ff461e9034b9ebded07b2a9d3d88c2f75359d5c069ebb3ee4e9c6ec5c45cf8
uri: huggingface://Lewdiculous/experimental-lwd-Mirau-RP-14B-GGUF-IQ-Imatrix/lwd-Mirau-RP-Q4_K_M-imat.gguf uri: huggingface://Lewdiculous/experimental-lwd-Mirau-RP-14B-GGUF-IQ-Imatrix/lwd-Mirau-RP-Q4_K_M-imat.gguf
- !!merge <<: *qwen25
name: "32b-qwen2.5-kunou-v1"
icon: https://huggingface.co/Sao10K/72B-Qwen2.5-Kunou-v1/resolve/main/knn.png
urls:
- https://huggingface.co/Sao10K/32B-Qwen2.5-Kunou-v1
- https://huggingface.co/bartowski/32B-Qwen2.5-Kunou-v1-GGUF
description: |
I do not really have anything planned for this model other than it being a generalist, and Roleplay Model? It was just something made and planned in minutes.
Same with the 14B and 72B version.
Kunou's the name of an OC I worked on for a couple of years, for a... fanfic. mmm...
A kind-of successor to L3-70B-Euryale-v2.2 in all but name? I'm keeping Stheno/Euryale lineage to Llama series for now.
I had a version made on top of Nemotron, a supposed Euryale 2.4 but that flopped hard, it was not my cup of tea.
This version is basically a better, more cleaned up Dataset used on Euryale and Stheno.
overrides:
parameters:
model: 32B-Qwen2.5-Kunou-v1-Q4_K_M.gguf
files:
- filename: 32B-Qwen2.5-Kunou-v1-Q4_K_M.gguf
sha256: b8910172b74d03c3463ac301589f54b96e54f61c67531fb6b523ecfe923aaffb
uri: huggingface://bartowski/32B-Qwen2.5-Kunou-v1-GGUF/32B-Qwen2.5-Kunou-v1-Q4_K_M.gguf
- !!merge <<: *qwen25
name: "14b-qwen2.5-kunou-v1"
urls:
- https://huggingface.co/Sao10K/14B-Qwen2.5-Kunou-v1
- https://huggingface.co/DevQuasar/Sao10K.14B-Qwen2.5-Kunou-v1-GGUF
description: |
I do not really have anything planned for this model other than it being a generalist, and Roleplay Model? It was just something made and planned in minutes.
This is the little sister variant, the small 14B version.
Kunou's the name of an OC I worked on for a couple of years, for a... fanfic. mmm...
A kind-of successor to my smaller model series. It works pretty nicely I think?
This version is basically a better, more cleaned up Dataset used on Euryale and Stheno.
overrides:
parameters:
model: Sao10K.14B-Qwen2.5-Kunou-v1.Q4_K_M.gguf
files:
- filename: Sao10K.14B-Qwen2.5-Kunou-v1.Q4_K_M.gguf
sha256: 7b7af50076e15c305a2a1bed7ad766dc6deb61eef3c2e6a40d4c94ad45623845
uri: huggingface://DevQuasar/Sao10K.14B-Qwen2.5-Kunou-v1-GGUF/Sao10K.14B-Qwen2.5-Kunou-v1.Q4_K_M.gguf
- !!merge <<: *qwen25
name: "dolphin3.0-qwen2.5-0.5b"
icon: https://cdn-uploads.huggingface.co/production/uploads/63111b2d88942700629f5771/cNCs1TBD3FelWCJGkZ3cd.png
urls:
- https://huggingface.co/cognitivecomputations/Dolphin3.0-Qwen2.5-0.5B
- https://huggingface.co/bartowski/Dolphin3.0-Qwen2.5-0.5B-GGUF
description: |
Dolphin 3.0 is the next generation of the Dolphin series of instruct-tuned models. Designed to be the ultimate general purpose local model, enabling coding, math, agentic, function calling, and general use cases.
Dolphin aims to be a general purpose model, similar to the models behind ChatGPT, Claude, Gemini. But these models present problems for businesses seeking to include AI in their products.
They maintain control of the system prompt, deprecating and changing things as they wish, often causing software to break.
They maintain control of the model versions, sometimes changing things silently, or deprecating older models that your business relies on.
They maintain control of the alignment, and in particular the alignment is one-size-fits all, not tailored to the application.
They can see all your queries and they can potentially use that data in ways you wouldn't want. Dolphin, in contrast, is steerable and gives control to the system owner. You set the system prompt. You decide the alignment. You have control of your data. Dolphin does not impose its ethics or guidelines on you. You are the one who decides the guidelines.
Dolphin belongs to YOU, it is your tool, an extension of your will. Just as you are personally responsible for what you do with a knife, gun, fire, car, or the internet, you are the creator and originator of any content you generate with Dolphin.
overrides:
parameters:
model: Dolphin3.0-Qwen2.5-0.5B-Q4_K_M.gguf
files:
- filename: Dolphin3.0-Qwen2.5-0.5B-Q4_K_M.gguf
sha256: 6a53689e2cb91027fdc9e366142eba8e35f56c14ee353e0a4d64de981efbfffa
uri: huggingface://bartowski/Dolphin3.0-Qwen2.5-0.5B-GGUF/Dolphin3.0-Qwen2.5-0.5B-Q4_K_M.gguf
- !!merge <<: *qwen25
name: "dolphin3.0-qwen2.5-1.5b"
url: "github:mudler/LocalAI/gallery/chatml.yaml@master"
icon: https://cdn-uploads.huggingface.co/production/uploads/63111b2d88942700629f5771/cNCs1TBD3FelWCJGkZ3cd.png
urls:
- https://huggingface.co/cognitivecomputations/Dolphin3.0-Qwen2.5-1.5B
- https://huggingface.co/bartowski/Dolphin3.0-Qwen2.5-1.5B-GGUF
description: |
Dolphin 3.0 is the next generation of the Dolphin series of instruct-tuned models. Designed to be the ultimate general purpose local model, enabling coding, math, agentic, function calling, and general use cases.
Dolphin aims to be a general purpose model, similar to the models behind ChatGPT, Claude, Gemini. But these models present problems for businesses seeking to include AI in their products.
They maintain control of the system prompt, deprecating and changing things as they wish, often causing software to break.
They maintain control of the model versions, sometimes changing things silently, or deprecating older models that your business relies on.
They maintain control of the alignment, and in particular the alignment is one-size-fits all, not tailored to the application.
They can see all your queries and they can potentially use that data in ways you wouldn't want. Dolphin, in contrast, is steerable and gives control to the system owner. You set the system prompt. You decide the alignment. You have control of your data. Dolphin does not impose its ethics or guidelines on you. You are the one who decides the guidelines.
Dolphin belongs to YOU, it is your tool, an extension of your will. Just as you are personally responsible for what you do with a knife, gun, fire, car, or the internet, you are the creator and originator of any content you generate with Dolphin.
overrides:
parameters:
model: Dolphin3.0-Qwen2.5-1.5B-Q4_K_M.gguf
files:
- filename: Dolphin3.0-Qwen2.5-1.5B-Q4_K_M.gguf
sha256: 7caa630a60c8831a509e2663e1761355fa24bcf6ccc03e3cc767e5b5747a3be5
uri: huggingface://bartowski/Dolphin3.0-Qwen2.5-1.5B-GGUF/Dolphin3.0-Qwen2.5-1.5B-Q4_K_M.gguf
- !!merge <<: *qwen25
name: "dolphin3.0-qwen2.5-3b"
icon: https://cdn-uploads.huggingface.co/production/uploads/63111b2d88942700629f5771/cNCs1TBD3FelWCJGkZ3cd.png
url: "github:mudler/LocalAI/gallery/chatml.yaml@master"
urls:
- https://huggingface.co/cognitivecomputations/Dolphin3.0-Qwen2.5-3b
- https://huggingface.co/bartowski/Dolphin3.0-Qwen2.5-3b-GGUF
description: |
Dolphin 3.0 is the next generation of the Dolphin series of instruct-tuned models. Designed to be the ultimate general purpose local model, enabling coding, math, agentic, function calling, and general use cases.
Dolphin aims to be a general purpose model, similar to the models behind ChatGPT, Claude, Gemini. But these models present problems for businesses seeking to include AI in their products.
They maintain control of the system prompt, deprecating and changing things as they wish, often causing software to break.
They maintain control of the model versions, sometimes changing things silently, or deprecating older models that your business relies on.
They maintain control of the alignment, and in particular the alignment is one-size-fits all, not tailored to the application.
They can see all your queries and they can potentially use that data in ways you wouldn't want. Dolphin, in contrast, is steerable and gives control to the system owner. You set the system prompt. You decide the alignment. You have control of your data. Dolphin does not impose its ethics or guidelines on you. You are the one who decides the guidelines.
Dolphin belongs to YOU, it is your tool, an extension of your will. Just as you are personally responsible for what you do with a knife, gun, fire, car, or the internet, you are the creator and originator of any content you generate with Dolphin.
overrides:
parameters:
model: Dolphin3.0-Qwen2.5-3b-Q4_K_M.gguf
files:
- filename: Dolphin3.0-Qwen2.5-3b-Q4_K_M.gguf
sha256: 0cb1908c5f444e1dc2c5b5619d62ac4957a22ad39cd42f2d0b48e2d8b1c358ab
uri: huggingface://bartowski/Dolphin3.0-Qwen2.5-3b-GGUF/Dolphin3.0-Qwen2.5-3b-Q4_K_M.gguf
- &smollm - &smollm
## SmolLM ## SmolLM
url: "github:mudler/LocalAI/gallery/chatml.yaml@master" url: "github:mudler/LocalAI/gallery/chatml.yaml@master"
@ -4571,6 +4734,31 @@
- filename: Llama3.1-8B-PRM-Deepseek-Data.Q4_K_M.gguf - filename: Llama3.1-8B-PRM-Deepseek-Data.Q4_K_M.gguf
sha256: 254c7ccc4ea3818fe5f6e3ffd5500c779b02058b98f9ce9a3856e54106d008e3 sha256: 254c7ccc4ea3818fe5f6e3ffd5500c779b02058b98f9ce9a3856e54106d008e3
uri: huggingface://QuantFactory/Llama3.1-8B-PRM-Deepseek-Data-GGUF/Llama3.1-8B-PRM-Deepseek-Data.Q4_K_M.gguf uri: huggingface://QuantFactory/Llama3.1-8B-PRM-Deepseek-Data-GGUF/Llama3.1-8B-PRM-Deepseek-Data.Q4_K_M.gguf
- !!merge <<: *llama31
name: "dolphin3.0-llama3.1-8b"
url: "github:mudler/LocalAI/gallery/chatml.yaml@master"
icon: https://cdn-uploads.huggingface.co/production/uploads/63111b2d88942700629f5771/cNCs1TBD3FelWCJGkZ3cd.png
urls:
- https://huggingface.co/cognitivecomputations/Dolphin3.0-Llama3.1-8B
- https://huggingface.co/bartowski/Dolphin3.0-Llama3.1-8B-GGUF
description: |
Dolphin 3.0 is the next generation of the Dolphin series of instruct-tuned models. Designed to be the ultimate general purpose local model, enabling coding, math, agentic, function calling, and general use cases.
Dolphin aims to be a general purpose model, similar to the models behind ChatGPT, Claude, Gemini. But these models present problems for businesses seeking to include AI in their products.
They maintain control of the system prompt, deprecating and changing things as they wish, often causing software to break.
They maintain control of the model versions, sometimes changing things silently, or deprecating older models that your business relies on.
They maintain control of the alignment, and in particular the alignment is one-size-fits all, not tailored to the application.
They can see all your queries and they can potentially use that data in ways you wouldn't want. Dolphin, in contrast, is steerable and gives control to the system owner. You set the system prompt. You decide the alignment. You have control of your data. Dolphin does not impose its ethics or guidelines on you. You are the one who decides the guidelines.
Dolphin belongs to YOU, it is your tool, an extension of your will. Just as you are personally responsible for what you do with a knife, gun, fire, car, or the internet, you are the creator and originator of any content you generate with Dolphin.
overrides:
parameters:
model: Dolphin3.0-Llama3.1-8B-Q4_K_M.gguf
files:
- filename: Dolphin3.0-Llama3.1-8B-Q4_K_M.gguf
sha256: 268390e07edd407ad93ea21a868b7ae995b5950e01cad0db9e1802ae5049d405
uri: huggingface://bartowski/Dolphin3.0-Llama3.1-8B-GGUF/Dolphin3.0-Llama3.1-8B-Q4_K_M.gguf
- &deepseek - &deepseek
## Deepseek ## Deepseek
url: "github:mudler/LocalAI/gallery/deepseek.yaml@master" url: "github:mudler/LocalAI/gallery/deepseek.yaml@master"
@ -9289,6 +9477,29 @@
- filename: Bio-Medical-Llama-3-8B.Q4_K_M.gguf - filename: Bio-Medical-Llama-3-8B.Q4_K_M.gguf
sha256: 672939e0487d02c55734132c25a59f26e4deaac7cd49445a7028f2291139edcc sha256: 672939e0487d02c55734132c25a59f26e4deaac7cd49445a7028f2291139edcc
uri: huggingface://QuantFactory/Bio-Medical-Llama-3-8B-GGUF/Bio-Medical-Llama-3-8B.Q4_K_M.gguf uri: huggingface://QuantFactory/Bio-Medical-Llama-3-8B-GGUF/Bio-Medical-Llama-3-8B.Q4_K_M.gguf
- !!merge <<: *llama3
name: "triangulum-10b"
icon: https://cdn-uploads.huggingface.co/production/uploads/65bb837dbfb878f46c77de4c/By0OJ1lMvP5ZvVvfEGvz5.png
urls:
- https://huggingface.co/prithivMLmods/Triangulum-10B
- https://huggingface.co/mradermacher/Triangulum-10B-GGUF
description: |
Triangulum 10B is a collection of pretrained and instruction-tuned generative models, designed for multilingual applications. These models are trained using synthetic datasets based on long chains of thought, enabling them to perform complex reasoning tasks effectively.
Key Features
Foundation Model: Built upon LLaMA's autoregressive language model, leveraging an optimized transformer architecture for enhanced performance.
Instruction Tuning: Includes supervised fine-tuning (SFT) and reinforcement learning with human feedback (RLHF) to align model outputs with human preferences for helpfulness and safety.
Multilingual Support: Designed to handle multiple languages, ensuring broad applicability across diverse linguistic contexts.
Training Approach
Synthetic Datasets: Utilizes long chain-of-thought synthetic data to enhance reasoning capabilities.
Supervised Fine-Tuning (SFT): Aligns the model to specific tasks through curated datasets.
Reinforcement Learning with Human Feedback (RLHF): Ensures the model adheres to human values and safety guidelines through iterative training processes.
overrides:
parameters:
model: Triangulum-10B.Q4_K_M.gguf
files:
- filename: Triangulum-10B.Q4_K_M.gguf
sha256: dd071f99edf6b166044bf229cdeec19419c4c348e3fc3d6587cfcc55e6fb85fa
uri: huggingface://mradermacher/Triangulum-10B-GGUF/Triangulum-10B.Q4_K_M.gguf
- &command-R - &command-R
### START Command-r ### START Command-r
url: "github:mudler/LocalAI/gallery/command-r.yaml@master" url: "github:mudler/LocalAI/gallery/command-r.yaml@master"