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