mirror of
https://github.com/mudler/LocalAI.git
synced 2025-05-29 15:04:59 +00:00

Some checks are pending
Explorer deployment / build-linux (push) Waiting to run
GPU tests / ubuntu-latest (1.21.x) (push) Waiting to run
generate and publish intel docker caches / generate_caches (intel/oneapi-basekit:2025.1.0-0-devel-ubuntu22.04, linux/amd64, ubuntu-latest) (push) Waiting to run
build container images / hipblas-jobs (-aio-gpu-hipblas, rocm/dev-ubuntu-22.04:6.1, hipblas, true, ubuntu:22.04, extras, latest-gpu-hipblas-extras, latest-aio-gpu-hipblas, --jobs=3 --output-sync=target, linux/amd64, arc-runner-set, auto, -hipblas-extras) (push) Waiting to run
build container images / hipblas-jobs (rocm/dev-ubuntu-22.04:6.1, hipblas, true, ubuntu:22.04, core, latest-gpu-hipblas, --jobs=3 --output-sync=target, linux/amd64, arc-runner-set, false, -hipblas) (push) Waiting to run
build container images / self-hosted-jobs (-aio-gpu-intel-f16, quay.io/go-skynet/intel-oneapi-base:latest, sycl_f16, true, ubuntu:22.04, extras, latest-gpu-intel-f16-extras, latest-aio-gpu-intel-f16, --jobs=3 --output-sync=target, linux/amd64, arc-runner-set, false, -sycl-f16-… (push) Waiting to run
build container images / self-hosted-jobs (-aio-gpu-intel-f32, quay.io/go-skynet/intel-oneapi-base:latest, sycl_f32, true, ubuntu:22.04, extras, latest-gpu-intel-f32-extras, latest-aio-gpu-intel-f32, --jobs=3 --output-sync=target, linux/amd64, arc-runner-set, false, -sycl-f32-… (push) Waiting to run
build container images / self-hosted-jobs (-aio-gpu-nvidia-cuda-11, ubuntu:22.04, cublas, 11, 7, true, extras, latest-gpu-nvidia-cuda-11-extras, latest-aio-gpu-nvidia-cuda-11, --jobs=3 --output-sync=target, linux/amd64, arc-runner-set, false, -cublas-cuda11-extras) (push) Waiting to run
build container images / self-hosted-jobs (-aio-gpu-nvidia-cuda-12, ubuntu:22.04, cublas, 12, 0, true, extras, latest-gpu-nvidia-cuda-12-extras, latest-aio-gpu-nvidia-cuda-12, --jobs=3 --output-sync=target, linux/amd64, arc-runner-set, false, -cublas-cuda12-extras) (push) Waiting to run
build container images / self-hosted-jobs (quay.io/go-skynet/intel-oneapi-base:latest, sycl_f16, true, ubuntu:22.04, core, latest-gpu-intel-f16, --jobs=3 --output-sync=target, linux/amd64, arc-runner-set, false, -sycl-f16) (push) Waiting to run
build container images / self-hosted-jobs (quay.io/go-skynet/intel-oneapi-base:latest, sycl_f32, true, ubuntu:22.04, core, latest-gpu-intel-f32, --jobs=3 --output-sync=target, linux/amd64, arc-runner-set, false, -sycl-f32) (push) Waiting to run
build container images / core-image-build (-aio-cpu, ubuntu:22.04, , true, core, latest-cpu, latest-aio-cpu, --jobs=4 --output-sync=target, linux/amd64,linux/arm64, arc-runner-set, false, auto, ) (push) Waiting to run
build container images / core-image-build (ubuntu:22.04, cublas, 11, 7, true, core, latest-gpu-nvidia-cuda-12, --jobs=4 --output-sync=target, linux/amd64, arc-runner-set, false, false, -cublas-cuda11) (push) Waiting to run
build container images / core-image-build (ubuntu:22.04, cublas, 12, 0, true, core, latest-gpu-nvidia-cuda-12, --jobs=4 --output-sync=target, linux/amd64, arc-runner-set, false, false, -cublas-cuda12) (push) Waiting to run
build container images / core-image-build (ubuntu:22.04, vulkan, true, core, latest-gpu-vulkan, --jobs=4 --output-sync=target, linux/amd64, arc-runner-set, false, false, -vulkan) (push) Waiting to run
build container images / gh-runner (nvcr.io/nvidia/l4t-jetpack:r36.4.0, cublas, 12, 0, true, core, latest-nvidia-l4t-arm64, --jobs=4 --output-sync=target, linux/arm64, ubuntu-24.04-arm, true, false, -nvidia-l4t-arm64) (push) Waiting to run
Security Scan / tests (push) Waiting to run
Tests extras backends / tests-transformers (push) Waiting to run
Tests extras backends / tests-rerankers (push) Waiting to run
Tests extras backends / tests-diffusers (push) Waiting to run
Tests extras backends / tests-coqui (push) Waiting to run
tests / tests-linux (1.21.x) (push) Waiting to run
tests / tests-aio-container (push) Waiting to run
tests / tests-apple (1.21.x) (push) Waiting to run
* feat(realtime): Initial Realtime API implementation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * chore: go mod tidy Signed-off-by: Richard Palethorpe <io@richiejp.com> * feat: Implement transcription only mode for realtime API Reduce the scope of the real time API for the initial realease and make transcription only mode functional. Signed-off-by: Richard Palethorpe <io@richiejp.com> * chore(build): Build backends on a separate layer to speed up core only changes Signed-off-by: Richard Palethorpe <io@richiejp.com> --------- Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Signed-off-by: Richard Palethorpe <io@richiejp.com> Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
225 lines
7.3 KiB
Go
225 lines
7.3 KiB
Go
package http
|
|
|
|
import (
|
|
"embed"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/dave-gray101/v2keyauth"
|
|
"github.com/gofiber/websocket/v2"
|
|
"github.com/mudler/LocalAI/pkg/utils"
|
|
|
|
"github.com/mudler/LocalAI/core/http/endpoints/localai"
|
|
"github.com/mudler/LocalAI/core/http/endpoints/openai"
|
|
"github.com/mudler/LocalAI/core/http/middleware"
|
|
"github.com/mudler/LocalAI/core/http/routes"
|
|
|
|
"github.com/mudler/LocalAI/core/application"
|
|
"github.com/mudler/LocalAI/core/schema"
|
|
"github.com/mudler/LocalAI/core/services"
|
|
|
|
"github.com/gofiber/contrib/fiberzerolog"
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/gofiber/fiber/v2/middleware/cors"
|
|
"github.com/gofiber/fiber/v2/middleware/csrf"
|
|
"github.com/gofiber/fiber/v2/middleware/favicon"
|
|
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
|
"github.com/gofiber/fiber/v2/middleware/recover"
|
|
|
|
// swagger handler
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
// Embed a directory
|
|
//
|
|
//go:embed static/*
|
|
var embedDirStatic embed.FS
|
|
|
|
// @title LocalAI API
|
|
// @version 2.0.0
|
|
// @description The LocalAI Rest API.
|
|
// @termsOfService
|
|
// @contact.name LocalAI
|
|
// @contact.url https://localai.io
|
|
// @license.name MIT
|
|
// @license.url https://raw.githubusercontent.com/mudler/LocalAI/master/LICENSE
|
|
// @BasePath /
|
|
// @securityDefinitions.apikey BearerAuth
|
|
// @in header
|
|
// @name Authorization
|
|
|
|
func API(application *application.Application) (*fiber.App, error) {
|
|
|
|
fiberCfg := fiber.Config{
|
|
Views: renderEngine(),
|
|
BodyLimit: application.ApplicationConfig().UploadLimitMB * 1024 * 1024, // this is the default limit of 4MB
|
|
// We disable the Fiber startup message as it does not conform to structured logging.
|
|
// We register a startup log line with connection information in the OnListen hook to keep things user friendly though
|
|
DisableStartupMessage: true,
|
|
// Override default error handler
|
|
}
|
|
|
|
if !application.ApplicationConfig().OpaqueErrors {
|
|
// Normally, return errors as JSON responses
|
|
fiberCfg.ErrorHandler = func(ctx *fiber.Ctx, err error) error {
|
|
// Status code defaults to 500
|
|
code := fiber.StatusInternalServerError
|
|
|
|
// Retrieve the custom status code if it's a *fiber.Error
|
|
var e *fiber.Error
|
|
if errors.As(err, &e) {
|
|
code = e.Code
|
|
}
|
|
|
|
// Send custom error page
|
|
return ctx.Status(code).JSON(
|
|
schema.ErrorResponse{
|
|
Error: &schema.APIError{Message: err.Error(), Code: code},
|
|
},
|
|
)
|
|
}
|
|
} else {
|
|
// If OpaqueErrors are required, replace everything with a blank 500.
|
|
fiberCfg.ErrorHandler = func(ctx *fiber.Ctx, _ error) error {
|
|
return ctx.Status(500).SendString("")
|
|
}
|
|
}
|
|
|
|
router := fiber.New(fiberCfg)
|
|
|
|
router.Use(middleware.StripPathPrefix())
|
|
|
|
if application.ApplicationConfig().MachineTag != "" {
|
|
router.Use(func(c *fiber.Ctx) error {
|
|
c.Response().Header.Set("Machine-Tag", application.ApplicationConfig().MachineTag)
|
|
|
|
return c.Next()
|
|
})
|
|
}
|
|
|
|
router.Use("/v1/realtime", func(c *fiber.Ctx) error {
|
|
if websocket.IsWebSocketUpgrade(c) {
|
|
// Returns true if the client requested upgrade to the WebSocket protocol
|
|
return c.Next()
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
router.Hooks().OnListen(func(listenData fiber.ListenData) error {
|
|
scheme := "http"
|
|
if listenData.TLS {
|
|
scheme = "https"
|
|
}
|
|
log.Info().Str("endpoint", scheme+"://"+listenData.Host+":"+listenData.Port).Msg("LocalAI API is listening! Please connect to the endpoint for API documentation.")
|
|
return nil
|
|
})
|
|
|
|
// Have Fiber use zerolog like the rest of the application rather than it's built-in logger
|
|
logger := log.Logger
|
|
router.Use(fiberzerolog.New(fiberzerolog.Config{
|
|
Logger: &logger,
|
|
}))
|
|
|
|
// Default middleware config
|
|
|
|
if !application.ApplicationConfig().Debug {
|
|
router.Use(recover.New())
|
|
}
|
|
|
|
if !application.ApplicationConfig().DisableMetrics {
|
|
metricsService, err := services.NewLocalAIMetricsService()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if metricsService != nil {
|
|
router.Use(localai.LocalAIMetricsAPIMiddleware(metricsService))
|
|
router.Hooks().OnShutdown(func() error {
|
|
return metricsService.Shutdown()
|
|
})
|
|
}
|
|
}
|
|
// Health Checks should always be exempt from auth, so register these first
|
|
routes.HealthRoutes(router)
|
|
|
|
kaConfig, err := middleware.GetKeyAuthConfig(application.ApplicationConfig())
|
|
if err != nil || kaConfig == nil {
|
|
return nil, fmt.Errorf("failed to create key auth config: %w", err)
|
|
}
|
|
|
|
httpFS := http.FS(embedDirStatic)
|
|
|
|
router.Use(favicon.New(favicon.Config{
|
|
URL: "/favicon.svg",
|
|
FileSystem: httpFS,
|
|
File: "static/favicon.svg",
|
|
}))
|
|
|
|
router.Use("/static", filesystem.New(filesystem.Config{
|
|
Root: httpFS,
|
|
PathPrefix: "static",
|
|
Browse: true,
|
|
}))
|
|
|
|
if application.ApplicationConfig().GeneratedContentDir != "" {
|
|
os.MkdirAll(application.ApplicationConfig().GeneratedContentDir, 0750)
|
|
audioPath := filepath.Join(application.ApplicationConfig().GeneratedContentDir, "audio")
|
|
imagePath := filepath.Join(application.ApplicationConfig().GeneratedContentDir, "images")
|
|
videoPath := filepath.Join(application.ApplicationConfig().GeneratedContentDir, "videos")
|
|
|
|
os.MkdirAll(audioPath, 0750)
|
|
os.MkdirAll(imagePath, 0750)
|
|
os.MkdirAll(videoPath, 0750)
|
|
|
|
router.Static("/generated-audio", audioPath)
|
|
router.Static("/generated-images", imagePath)
|
|
router.Static("/generated-videos", videoPath)
|
|
}
|
|
|
|
// Auth is applied to _all_ endpoints. No exceptions. Filtering out endpoints to bypass is the role of the Filter property of the KeyAuth Configuration
|
|
router.Use(v2keyauth.New(*kaConfig))
|
|
|
|
if application.ApplicationConfig().CORS {
|
|
var c func(ctx *fiber.Ctx) error
|
|
if application.ApplicationConfig().CORSAllowOrigins == "" {
|
|
c = cors.New()
|
|
} else {
|
|
c = cors.New(cors.Config{AllowOrigins: application.ApplicationConfig().CORSAllowOrigins})
|
|
}
|
|
|
|
router.Use(c)
|
|
}
|
|
|
|
if application.ApplicationConfig().CSRF {
|
|
log.Debug().Msg("Enabling CSRF middleware. Tokens are now required for state-modifying requests")
|
|
router.Use(csrf.New())
|
|
}
|
|
|
|
// Load config jsons
|
|
utils.LoadConfig(application.ApplicationConfig().UploadDir, openai.UploadedFilesFile, &openai.UploadedFiles)
|
|
utils.LoadConfig(application.ApplicationConfig().ConfigsDir, openai.AssistantsConfigFile, &openai.Assistants)
|
|
utils.LoadConfig(application.ApplicationConfig().ConfigsDir, openai.AssistantsFileConfigFile, &openai.AssistantFiles)
|
|
|
|
galleryService := services.NewGalleryService(application.ApplicationConfig())
|
|
galleryService.Start(application.ApplicationConfig().Context, application.BackendLoader())
|
|
|
|
requestExtractor := middleware.NewRequestExtractor(application.BackendLoader(), application.ModelLoader(), application.ApplicationConfig())
|
|
|
|
routes.RegisterElevenLabsRoutes(router, requestExtractor, application.BackendLoader(), application.ModelLoader(), application.ApplicationConfig())
|
|
routes.RegisterLocalAIRoutes(router, requestExtractor, application.BackendLoader(), application.ModelLoader(), application.ApplicationConfig(), galleryService)
|
|
routes.RegisterOpenAIRoutes(router, requestExtractor, application)
|
|
if !application.ApplicationConfig().DisableWebUI {
|
|
routes.RegisterUIRoutes(router, application.BackendLoader(), application.ModelLoader(), application.ApplicationConfig(), galleryService)
|
|
}
|
|
routes.RegisterJINARoutes(router, requestExtractor, application.BackendLoader(), application.ModelLoader(), application.ApplicationConfig())
|
|
|
|
// Define a custom 404 handler
|
|
// Note: keep this at the bottom!
|
|
router.Use(notFoundHandler)
|
|
|
|
return router, nil
|
|
}
|