2024-02-21 01:21:19 +00:00
package http
2024-01-05 17:04:46 +00:00
import (
2024-05-02 19:14:10 +00:00
"embed"
2024-01-05 17:04:46 +00:00
"errors"
2024-09-17 03:29:07 +00:00
"fmt"
2024-05-02 19:14:10 +00:00
"net/http"
2024-01-05 17:04:46 +00:00
2024-09-17 03:29:07 +00:00
"github.com/dave-gray101/v2keyauth"
2024-10-02 09:16:11 +00:00
"github.com/gofiber/websocket/v2"
2024-06-23 08:24:36 +00:00
"github.com/mudler/LocalAI/pkg/utils"
2024-03-27 20:10:58 +00:00
2024-06-23 08:24:36 +00:00
"github.com/mudler/LocalAI/core/http/endpoints/localai"
"github.com/mudler/LocalAI/core/http/endpoints/openai"
2024-09-17 03:29:07 +00:00
"github.com/mudler/LocalAI/core/http/middleware"
2024-06-23 08:24:36 +00:00
"github.com/mudler/LocalAI/core/http/routes"
2024-04-17 21:33:49 +00:00
2024-12-08 12:50:33 +00:00
"github.com/mudler/LocalAI/core/application"
2024-06-23 08:24:36 +00:00
"github.com/mudler/LocalAI/core/schema"
"github.com/mudler/LocalAI/core/services"
2024-01-05 17:04:46 +00:00
2024-04-20 08:43:37 +00:00
"github.com/gofiber/contrib/fiberzerolog"
2024-01-05 17:04:46 +00:00
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
2024-06-04 19:43:46 +00:00
"github.com/gofiber/fiber/v2/middleware/csrf"
2024-05-07 06:39:23 +00:00
"github.com/gofiber/fiber/v2/middleware/favicon"
2024-05-02 19:14:10 +00:00
"github.com/gofiber/fiber/v2/middleware/filesystem"
2024-01-05 17:04:46 +00:00
"github.com/gofiber/fiber/v2/middleware/recover"
2024-04-20 08:43:37 +00:00
2024-04-20 23:19:57 +00:00
// swagger handler
2024-04-20 08:43:37 +00:00
"github.com/rs/zerolog/log"
2024-01-05 17:04:46 +00:00
)
2024-05-02 19:14:10 +00:00
// Embed a directory
//
//go:embed static/*
var embedDirStatic embed . FS
2024-03-29 21:29:33 +00:00
// @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
2024-04-17 21:33:49 +00:00
2024-12-08 12:50:33 +00:00
func API ( application * application . Application ) ( * fiber . App , error ) {
2024-06-05 06:45:24 +00:00
fiberCfg := fiber . Config {
2024-04-20 08:43:37 +00:00
Views : renderEngine ( ) ,
2024-12-08 12:50:33 +00:00
BodyLimit : application . ApplicationConfig ( ) . UploadLimitMB * 1024 * 1024 , // this is the default limit of 4MB
2024-04-20 08:43:37 +00:00
// 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 ,
2024-01-05 17:04:46 +00:00
// Override default error handler
2024-06-05 06:45:24 +00:00
}
2024-12-08 12:50:33 +00:00
if ! application . ApplicationConfig ( ) . OpaqueErrors {
2024-06-05 06:45:24 +00:00
// Normally, return errors as JSON responses
fiberCfg . ErrorHandler = func ( ctx * fiber . Ctx , err error ) error {
2024-01-05 17:04:46 +00:00
// 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 } ,
} ,
)
2024-06-05 06:45:24 +00:00
}
} else {
// If OpaqueErrors are required, replace everything with a blank 500.
fiberCfg . ErrorHandler = func ( ctx * fiber . Ctx , _ error ) error {
return ctx . Status ( 500 ) . SendString ( "" )
}
}
2024-12-08 12:50:33 +00:00
router := fiber . New ( fiberCfg )
2024-01-05 17:04:46 +00:00
2024-10-31 18:09:28 +00:00
router . Use ( 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
} )
2024-12-08 12:50:33 +00:00
router . Hooks ( ) . OnListen ( func ( listenData fiber . ListenData ) error {
2024-04-20 08:43:37 +00:00
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
2024-12-08 12:50:33 +00:00
router . Use ( fiberzerolog . New ( fiberzerolog . Config {
2024-04-20 08:43:37 +00:00
Logger : & logger ,
} ) )
2024-01-05 17:04:46 +00:00
// Default middleware config
2024-02-17 09:00:34 +00:00
2024-12-08 12:50:33 +00:00
if ! application . ApplicationConfig ( ) . Debug {
router . Use ( recover . New ( ) )
2024-02-17 09:00:34 +00:00
}
2024-12-08 12:50:33 +00:00
if ! application . ApplicationConfig ( ) . DisableMetrics {
2024-10-23 13:34:32 +00:00
metricsService , err := services . NewLocalAIMetricsService ( )
if err != nil {
return nil , err
}
2024-03-01 15:19:53 +00:00
2024-10-23 13:34:32 +00:00
if metricsService != nil {
2024-12-08 12:50:33 +00:00
router . Use ( localai . LocalAIMetricsAPIMiddleware ( metricsService ) )
router . Hooks ( ) . OnShutdown ( func ( ) error {
2024-10-23 13:34:32 +00:00
return metricsService . Shutdown ( )
} )
}
2024-01-05 17:04:46 +00:00
2024-10-23 13:34:32 +00:00
}
// Health Checks should always be exempt from auth, so register these first
2024-12-08 12:50:33 +00:00
routes . HealthRoutes ( router )
2024-09-24 18:25:59 +00:00
2024-12-08 12:50:33 +00:00
kaConfig , err := middleware . GetKeyAuthConfig ( application . ApplicationConfig ( ) )
2024-09-17 03:29:07 +00:00
if err != nil || kaConfig == nil {
return nil , fmt . Errorf ( "failed to create key auth config: %w" , err )
2024-01-05 17:04:46 +00:00
}
2024-09-17 03:29:07 +00:00
// Auth is applied to _all_ endpoints. No exceptions. Filtering out endpoints to bypass is the role of the Filter property of the KeyAuth Configuration
2024-12-08 12:50:33 +00:00
router . Use ( v2keyauth . New ( * kaConfig ) )
2024-09-17 03:29:07 +00:00
2024-12-08 12:50:33 +00:00
if application . ApplicationConfig ( ) . CORS {
2024-01-05 17:04:46 +00:00
var c func ( ctx * fiber . Ctx ) error
2024-12-08 12:50:33 +00:00
if application . ApplicationConfig ( ) . CORSAllowOrigins == "" {
2024-01-05 17:04:46 +00:00
c = cors . New ( )
} else {
2024-12-08 12:50:33 +00:00
c = cors . New ( cors . Config { AllowOrigins : application . ApplicationConfig ( ) . CORSAllowOrigins } )
2024-01-05 17:04:46 +00:00
}
2024-12-08 12:50:33 +00:00
router . Use ( c )
2024-01-05 17:04:46 +00:00
}
2024-12-08 12:50:33 +00:00
if application . ApplicationConfig ( ) . CSRF {
2024-06-04 19:43:46 +00:00
log . Debug ( ) . Msg ( "Enabling CSRF middleware. Tokens are now required for state-modifying requests" )
2024-12-08 12:50:33 +00:00
router . Use ( csrf . New ( ) )
2024-06-04 19:43:46 +00:00
}
2024-04-17 21:33:49 +00:00
// Load config jsons
2024-12-08 12:50:33 +00:00
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 ( ) )
routes . RegisterElevenLabsRoutes ( router , application . BackendLoader ( ) , application . ModelLoader ( ) , application . ApplicationConfig ( ) )
routes . RegisterLocalAIRoutes ( router , application . BackendLoader ( ) , application . ModelLoader ( ) , application . ApplicationConfig ( ) , galleryService )
routes . RegisterOpenAIRoutes ( router , application )
if ! application . ApplicationConfig ( ) . DisableWebUI {
routes . RegisterUIRoutes ( router , application . BackendLoader ( ) , application . ModelLoader ( ) , application . ApplicationConfig ( ) , galleryService )
2024-05-02 19:14:10 +00:00
}
2024-12-08 12:50:33 +00:00
routes . RegisterJINARoutes ( router , application . BackendLoader ( ) , application . ModelLoader ( ) , application . ApplicationConfig ( ) )
2024-01-05 17:04:46 +00:00
2024-05-07 06:39:23 +00:00
httpFS := http . FS ( embedDirStatic )
2024-12-08 12:50:33 +00:00
router . Use ( favicon . New ( favicon . Config {
2024-05-07 06:39:23 +00:00
URL : "/favicon.ico" ,
FileSystem : httpFS ,
File : "static/favicon.ico" ,
} ) )
2024-12-08 12:50:33 +00:00
router . Use ( "/static" , filesystem . New ( filesystem . Config {
2024-05-07 06:39:23 +00:00
Root : httpFS ,
2024-05-02 19:14:10 +00:00
PathPrefix : "static" ,
Browse : true ,
} ) )
2024-03-27 20:10:58 +00:00
// Define a custom 404 handler
2024-03-28 20:52:52 +00:00
// Note: keep this at the bottom!
2024-12-08 12:50:33 +00:00
router . Use ( notFoundHandler )
2024-03-27 20:10:58 +00:00
2024-12-08 12:50:33 +00:00
return router , nil
2024-01-05 17:04:46 +00:00
}