2024-02-21 01:21:19 +00:00
package http
2024-01-05 17:04:46 +00:00
import (
"errors"
"strings"
2024-04-13 07:45:34 +00:00
"github.com/go-skynet/LocalAI/core"
fiberContext "github.com/go-skynet/LocalAI/core/http/ctx"
2024-03-29 21:29:33 +00:00
"github.com/gofiber/swagger" // swagger handler
2024-03-27 20:10:58 +00:00
2024-03-14 22:08:34 +00:00
"github.com/go-skynet/LocalAI/core/http/endpoints/elevenlabs"
2024-03-01 15:19:53 +00:00
"github.com/go-skynet/LocalAI/core/http/endpoints/localai"
"github.com/go-skynet/LocalAI/core/http/endpoints/openai"
2024-02-21 01:21:19 +00:00
"github.com/go-skynet/LocalAI/core/schema"
2024-03-01 15:19:53 +00:00
"github.com/go-skynet/LocalAI/core/services"
2024-01-05 17:04:46 +00:00
"github.com/go-skynet/LocalAI/internal"
2024-04-13 07:45:34 +00:00
model "github.com/go-skynet/LocalAI/pkg/model"
2024-01-05 17:04:46 +00:00
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover"
)
2024-03-14 22:08:34 +00:00
func readAuthHeader ( c * fiber . Ctx ) string {
authHeader := c . Get ( "Authorization" )
// elevenlabs
xApiKey := c . Get ( "xi-api-key" )
if xApiKey != "" {
authHeader = "Bearer " + xApiKey
}
// anthropic
xApiKey = c . Get ( "x-api-key" )
if xApiKey != "" {
authHeader = "Bearer " + xApiKey
}
return authHeader
}
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-13 07:45:34 +00:00
func App ( application * core . Application ) ( * fiber . App , error ) {
2024-01-05 17:04:46 +00:00
// Return errors as JSON responses
app := fiber . New ( fiber . Config {
2024-03-28 20:52:52 +00:00
Views : renderEngine ( ) ,
2024-04-13 07:45:34 +00:00
BodyLimit : application . ApplicationConfig . UploadLimitMB * 1024 * 1024 , // this is the default limit of 4MB
DisableStartupMessage : application . ApplicationConfig . DisableMessage ,
2024-01-05 17:04:46 +00:00
// Override default error handler
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 } ,
} ,
)
} ,
} )
2024-04-13 07:45:34 +00:00
if application . ApplicationConfig . Debug {
2024-01-05 17:04:46 +00:00
app . Use ( logger . New ( logger . Config {
Format : "[${ip}]:${port} ${status} - ${method} ${path}\n" ,
} ) )
}
// Default middleware config
2024-02-17 09:00:34 +00:00
2024-04-13 07:45:34 +00:00
if ! application . ApplicationConfig . Debug {
2024-02-17 09:00:34 +00:00
app . Use ( recover . New ( ) )
}
2024-03-01 15:19:53 +00:00
metricsService , err := services . NewLocalAIMetricsService ( )
if err != nil {
return nil , err
}
if metricsService != nil {
app . Use ( localai . LocalAIMetricsAPIMiddleware ( metricsService ) )
app . Hooks ( ) . OnShutdown ( func ( ) error {
return metricsService . Shutdown ( )
} )
2024-01-05 17:04:46 +00:00
}
// Auth middleware checking if API key is valid. If no API key is set, no auth is required.
auth := func ( c * fiber . Ctx ) error {
2024-04-13 07:45:34 +00:00
if len ( application . ApplicationConfig . ApiKeys ) == 0 {
2024-01-05 17:04:46 +00:00
return c . Next ( )
}
2024-04-13 07:45:34 +00:00
// // Check for api_keys.json file
// fileContent, err := os.ReadFile("api_keys.json")
// if err == nil {
// // Parse JSON content from the file
// var fileKeys []string
// err := json.Unmarshal(fileContent, &fileKeys)
// if err != nil {
// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"message": "Error parsing api_keys.json"})
// }
2024-01-05 17:04:46 +00:00
2024-04-13 07:45:34 +00:00
// // Add file keys to options.ApiKeys
// application.ApplicationConfig.ApiKeys = append(application.ApplicationConfig.ApiKeys, fileKeys...)
// }
2024-01-05 17:04:46 +00:00
2024-04-13 07:45:34 +00:00
// if len(application.ApplicationConfig.ApiKeys) == 0 {
// return c.Next()
// }
2024-01-05 17:04:46 +00:00
2024-03-14 22:08:34 +00:00
authHeader := readAuthHeader ( c )
2024-01-05 17:04:46 +00:00
if authHeader == "" {
return c . Status ( fiber . StatusUnauthorized ) . JSON ( fiber . Map { "message" : "Authorization header missing" } )
}
2024-03-14 22:08:34 +00:00
// If it's a bearer token
2024-01-05 17:04:46 +00:00
authHeaderParts := strings . Split ( authHeader , " " )
if len ( authHeaderParts ) != 2 || authHeaderParts [ 0 ] != "Bearer" {
return c . Status ( fiber . StatusUnauthorized ) . JSON ( fiber . Map { "message" : "Invalid Authorization header format" } )
}
apiKey := authHeaderParts [ 1 ]
2024-04-13 07:45:34 +00:00
for _ , key := range application . ApplicationConfig . ApiKeys {
2024-01-05 17:04:46 +00:00
if apiKey == key {
return c . Next ( )
}
}
return c . Status ( fiber . StatusUnauthorized ) . JSON ( fiber . Map { "message" : "Invalid API key" } )
}
2024-04-13 07:45:34 +00:00
if application . ApplicationConfig . CORS {
2024-01-05 17:04:46 +00:00
var c func ( ctx * fiber . Ctx ) error
2024-04-13 07:45:34 +00:00
if application . ApplicationConfig . CORSAllowOrigins == "" {
2024-01-05 17:04:46 +00:00
c = cors . New ( )
} else {
2024-04-13 07:45:34 +00:00
c = cors . New ( cors . Config { AllowOrigins : application . ApplicationConfig . CORSAllowOrigins } )
2024-01-05 17:04:46 +00:00
}
app . Use ( c )
}
2024-04-13 07:45:34 +00:00
fiberContextExtractor := fiberContext . NewFiberContextExtractor ( application . ModelLoader , application . ApplicationConfig )
2024-01-05 17:04:46 +00:00
// LocalAI API endpoints
2024-04-13 07:45:34 +00:00
galleryService := services . NewGalleryService ( application . ApplicationConfig . ModelPath )
galleryService . Start ( application . ApplicationConfig . Context , application . BackendConfigLoader )
2024-01-05 17:04:46 +00:00
app . Get ( "/version" , auth , func ( c * fiber . Ctx ) error {
return c . JSON ( struct {
Version string ` json:"version" `
} { Version : internal . PrintableVersion ( ) } )
} )
2024-03-29 21:29:33 +00:00
app . Get ( "/swagger/*" , swagger . HandlerDefault ) // default
2024-03-28 20:52:52 +00:00
welcomeRoute (
app ,
2024-04-13 07:45:34 +00:00
application . BackendConfigLoader ,
application . ModelLoader ,
application . ApplicationConfig ,
2024-03-28 20:52:52 +00:00
auth ,
)
2024-03-27 20:10:58 +00:00
2024-04-13 07:45:34 +00:00
modelGalleryEndpointService := localai . CreateModelGalleryEndpointService ( application . ApplicationConfig . Galleries , application . ApplicationConfig . ModelPath , galleryService )
2024-03-01 15:19:53 +00:00
app . Post ( "/models/apply" , auth , modelGalleryEndpointService . ApplyModelGalleryEndpoint ( ) )
app . Get ( "/models/available" , auth , modelGalleryEndpointService . ListModelFromGalleryEndpoint ( ) )
app . Get ( "/models/galleries" , auth , modelGalleryEndpointService . ListModelGalleriesEndpoint ( ) )
app . Post ( "/models/galleries" , auth , modelGalleryEndpointService . AddModelGalleryEndpoint ( ) )
app . Delete ( "/models/galleries" , auth , modelGalleryEndpointService . RemoveModelGalleryEndpoint ( ) )
app . Get ( "/models/jobs/:uuid" , auth , modelGalleryEndpointService . GetOpStatusEndpoint ( ) )
app . Get ( "/models/jobs" , auth , modelGalleryEndpointService . GetAllStatusEndpoint ( ) )
2024-01-05 17:04:46 +00:00
2024-03-22 20:14:04 +00:00
// Stores
2024-04-13 07:45:34 +00:00
storeLoader := model . NewModelLoader ( "" ) // TODO: Investigate if this should be migrated to application and reused. Should the path be configurable? Merging for now.
app . Post ( "/stores/set" , auth , localai . StoresSetEndpoint ( storeLoader , application . ApplicationConfig ) )
app . Post ( "/stores/delete" , auth , localai . StoresDeleteEndpoint ( storeLoader , application . ApplicationConfig ) )
app . Post ( "/stores/get" , auth , localai . StoresGetEndpoint ( storeLoader , application . ApplicationConfig ) )
app . Post ( "/stores/find" , auth , localai . StoresFindEndpoint ( storeLoader , application . ApplicationConfig ) )
2024-03-22 20:14:04 +00:00
2024-04-13 07:45:34 +00:00
// openAI compatible API endpoints
2024-01-05 17:04:46 +00:00
// chat
2024-04-13 07:45:34 +00:00
app . Post ( "/v1/chat/completions" , auth , openai . ChatEndpoint ( fiberContextExtractor , application . OpenAIService ) )
app . Post ( "/chat/completions" , auth , openai . ChatEndpoint ( fiberContextExtractor , application . OpenAIService ) )
2024-01-05 17:04:46 +00:00
// edit
2024-04-13 07:45:34 +00:00
app . Post ( "/v1/edits" , auth , openai . EditEndpoint ( fiberContextExtractor , application . OpenAIService ) )
app . Post ( "/edits" , auth , openai . EditEndpoint ( fiberContextExtractor , application . OpenAIService ) )
2024-01-05 17:04:46 +00:00
2024-03-26 17:54:35 +00:00
// assistant
2024-04-13 07:45:34 +00:00
// TODO: Refactor this to the new style eventually
app . Get ( "/v1/assistants" , auth , openai . ListAssistantsEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Get ( "/assistants" , auth , openai . ListAssistantsEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Post ( "/v1/assistants" , auth , openai . CreateAssistantEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Post ( "/assistants" , auth , openai . CreateAssistantEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Delete ( "/v1/assistants/:assistant_id" , auth , openai . DeleteAssistantEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Delete ( "/assistants/:assistant_id" , auth , openai . DeleteAssistantEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Get ( "/v1/assistants/:assistant_id" , auth , openai . GetAssistantEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Get ( "/assistants/:assistant_id" , auth , openai . GetAssistantEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Post ( "/v1/assistants/:assistant_id" , auth , openai . ModifyAssistantEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Post ( "/assistants/:assistant_id" , auth , openai . ModifyAssistantEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Get ( "/v1/assistants/:assistant_id/files" , auth , openai . ListAssistantFilesEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Get ( "/assistants/:assistant_id/files" , auth , openai . ListAssistantFilesEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Post ( "/v1/assistants/:assistant_id/files" , auth , openai . CreateAssistantFileEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Post ( "/assistants/:assistant_id/files" , auth , openai . CreateAssistantFileEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Delete ( "/v1/assistants/:assistant_id/files/:file_id" , auth , openai . DeleteAssistantFileEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Delete ( "/assistants/:assistant_id/files/:file_id" , auth , openai . DeleteAssistantFileEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Get ( "/v1/assistants/:assistant_id/files/:file_id" , auth , openai . GetAssistantFileEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
app . Get ( "/assistants/:assistant_id/files/:file_id" , auth , openai . GetAssistantFileEndpoint ( application . BackendConfigLoader , application . ModelLoader , application . ApplicationConfig ) )
2024-03-26 17:54:35 +00:00
2024-02-18 10:12:02 +00:00
// files
2024-04-13 07:45:34 +00:00
app . Post ( "/v1/files" , auth , openai . UploadFilesEndpoint ( application . BackendConfigLoader , application . ApplicationConfig ) )
app . Post ( "/files" , auth , openai . UploadFilesEndpoint ( application . BackendConfigLoader , application . ApplicationConfig ) )
app . Get ( "/v1/files" , auth , openai . ListFilesEndpoint ( application . BackendConfigLoader , application . ApplicationConfig ) )
app . Get ( "/files" , auth , openai . ListFilesEndpoint ( application . BackendConfigLoader , application . ApplicationConfig ) )
app . Get ( "/v1/files/:file_id" , auth , openai . GetFilesEndpoint ( application . BackendConfigLoader , application . ApplicationConfig ) )
app . Get ( "/files/:file_id" , auth , openai . GetFilesEndpoint ( application . BackendConfigLoader , application . ApplicationConfig ) )
app . Delete ( "/v1/files/:file_id" , auth , openai . DeleteFilesEndpoint ( application . BackendConfigLoader , application . ApplicationConfig ) )
app . Delete ( "/files/:file_id" , auth , openai . DeleteFilesEndpoint ( application . BackendConfigLoader , application . ApplicationConfig ) )
app . Get ( "/v1/files/:file_id/content" , auth , openai . GetFilesContentsEndpoint ( application . BackendConfigLoader , application . ApplicationConfig ) )
app . Get ( "/files/:file_id/content" , auth , openai . GetFilesContentsEndpoint ( application . BackendConfigLoader , application . ApplicationConfig ) )
2024-02-18 10:12:02 +00:00
2024-01-05 17:04:46 +00:00
// completion
2024-04-13 07:45:34 +00:00
app . Post ( "/v1/completions" , auth , openai . CompletionEndpoint ( fiberContextExtractor , application . OpenAIService ) )
app . Post ( "/completions" , auth , openai . CompletionEndpoint ( fiberContextExtractor , application . OpenAIService ) )
app . Post ( "/v1/engines/:model/completions" , auth , openai . CompletionEndpoint ( fiberContextExtractor , application . OpenAIService ) )
2024-01-05 17:04:46 +00:00
// embeddings
2024-04-13 07:45:34 +00:00
app . Post ( "/v1/embeddings" , auth , openai . EmbeddingsEndpoint ( fiberContextExtractor , application . EmbeddingsBackendService ) )
app . Post ( "/embeddings" , auth , openai . EmbeddingsEndpoint ( fiberContextExtractor , application . EmbeddingsBackendService ) )
app . Post ( "/v1/engines/:model/embeddings" , auth , openai . EmbeddingsEndpoint ( fiberContextExtractor , application . EmbeddingsBackendService ) )
2024-01-05 17:04:46 +00:00
// audio
2024-04-13 07:45:34 +00:00
app . Post ( "/v1/audio/transcriptions" , auth , openai . TranscriptEndpoint ( fiberContextExtractor , application . TranscriptionBackendService ) )
app . Post ( "/v1/audio/speech" , auth , localai . TTSEndpoint ( fiberContextExtractor , application . TextToSpeechBackendService ) )
2024-01-05 17:04:46 +00:00
// images
2024-04-13 07:45:34 +00:00
app . Post ( "/v1/images/generations" , auth , openai . ImageEndpoint ( fiberContextExtractor , application . ImageGenerationBackendService ) )
// Elevenlabs
app . Post ( "/v1/text-to-speech/:voice-id" , auth , elevenlabs . TTSEndpoint ( fiberContextExtractor , application . TextToSpeechBackendService ) )
// LocalAI TTS?
app . Post ( "/tts" , auth , localai . TTSEndpoint ( fiberContextExtractor , application . TextToSpeechBackendService ) )
2024-01-05 17:04:46 +00:00
2024-04-13 07:45:34 +00:00
if application . ApplicationConfig . ImageDir != "" {
app . Static ( "/generated-images" , application . ApplicationConfig . ImageDir )
2024-01-05 17:04:46 +00:00
}
2024-04-13 07:45:34 +00:00
if application . ApplicationConfig . AudioDir != "" {
app . Static ( "/generated-audio" , application . ApplicationConfig . AudioDir )
2024-01-05 17:04:46 +00:00
}
ok := func ( c * fiber . Ctx ) error {
return c . SendStatus ( 200 )
}
// Kubernetes health checks
app . Get ( "/healthz" , ok )
app . Get ( "/readyz" , ok )
// Experimental Backend Statistics Module
2024-04-13 07:45:34 +00:00
app . Get ( "/backend/monitor" , auth , localai . BackendMonitorEndpoint ( application . BackendMonitorService ) )
app . Post ( "/backend/shutdown" , auth , localai . BackendShutdownEndpoint ( application . BackendMonitorService ) )
2024-01-05 17:04:46 +00:00
// models
2024-04-13 07:45:34 +00:00
app . Get ( "/v1/models" , auth , openai . ListModelsEndpoint ( application . ListModelsService ) )
app . Get ( "/models" , auth , openai . ListModelsEndpoint ( application . ListModelsService ) )
2024-01-05 17:04:46 +00:00
2024-03-28 20:52:52 +00:00
app . Get ( "/metrics" , auth , localai . LocalAIMetricsEndpoint ( ) )
2024-01-05 17:04:46 +00:00
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!
app . Use ( notFoundHandler )
2024-03-27 20:10:58 +00:00
2024-01-05 17:04:46 +00:00
return app , nil
}