mirror of
https://github.com/mudler/LocalAI.git
synced 2024-12-29 17:08:52 +00:00
a1634b219a
* initial pass: roll out bluemonday sanitization more widely Signed-off-by: Dave Lee <dave@gray101.com> * add one additional sanitize - the overall modelslist used by the docs site Signed-off-by: Dave Lee <dave@gray101.com> --------- Signed-off-by: Dave Lee <dave@gray101.com>
195 lines
5.9 KiB
Go
195 lines
5.9 KiB
Go
package openai
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/microcosm-cc/bluemonday"
|
|
"github.com/mudler/LocalAI/core/config"
|
|
"github.com/mudler/LocalAI/core/schema"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/mudler/LocalAI/pkg/utils"
|
|
)
|
|
|
|
var UploadedFiles []schema.File
|
|
|
|
const UploadedFilesFile = "uploadedFiles.json"
|
|
|
|
// UploadFilesEndpoint https://platform.openai.com/docs/api-reference/files/create
|
|
func UploadFilesEndpoint(cm *config.BackendConfigLoader, appConfig *config.ApplicationConfig) func(c *fiber.Ctx) error {
|
|
return func(c *fiber.Ctx) error {
|
|
file, err := c.FormFile("file")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Check the file size
|
|
if file.Size > int64(appConfig.UploadLimitMB*1024*1024) {
|
|
return c.Status(fiber.StatusBadRequest).SendString(fmt.Sprintf("File size %d exceeds upload limit %d", file.Size, appConfig.UploadLimitMB))
|
|
}
|
|
|
|
purpose := c.FormValue("purpose", "") //TODO put in purpose dirs
|
|
if purpose == "" {
|
|
return c.Status(fiber.StatusBadRequest).SendString("Purpose is not defined")
|
|
}
|
|
|
|
// Sanitize the filename to prevent directory traversal
|
|
filename := utils.SanitizeFileName(file.Filename)
|
|
|
|
savePath := filepath.Join(appConfig.UploadDir, filename)
|
|
|
|
// Check if file already exists
|
|
if _, err := os.Stat(savePath); !os.IsNotExist(err) {
|
|
return c.Status(fiber.StatusBadRequest).SendString("File already exists")
|
|
}
|
|
|
|
err = c.SaveFile(file, savePath)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).SendString("Failed to save file: " + bluemonday.StrictPolicy().Sanitize(err.Error()))
|
|
}
|
|
|
|
f := schema.File{
|
|
ID: fmt.Sprintf("file-%d", getNextFileId()),
|
|
Object: "file",
|
|
Bytes: int(file.Size),
|
|
CreatedAt: time.Now(),
|
|
Filename: file.Filename,
|
|
Purpose: purpose,
|
|
}
|
|
|
|
UploadedFiles = append(UploadedFiles, f)
|
|
utils.SaveConfig(appConfig.UploadDir, UploadedFilesFile, UploadedFiles)
|
|
return c.Status(fiber.StatusOK).JSON(f)
|
|
}
|
|
}
|
|
|
|
var currentFileId int64 = 0
|
|
|
|
func getNextFileId() int64 {
|
|
atomic.AddInt64(¤tId, 1)
|
|
return currentId
|
|
}
|
|
|
|
// ListFilesEndpoint https://platform.openai.com/docs/api-reference/files/list
|
|
// @Summary List files.
|
|
// @Success 200 {object} schema.ListFiles "Response"
|
|
// @Router /v1/files [get]
|
|
func ListFilesEndpoint(cm *config.BackendConfigLoader, appConfig *config.ApplicationConfig) func(c *fiber.Ctx) error {
|
|
|
|
return func(c *fiber.Ctx) error {
|
|
var listFiles schema.ListFiles
|
|
|
|
purpose := c.Query("purpose")
|
|
if purpose == "" {
|
|
listFiles.Data = UploadedFiles
|
|
} else {
|
|
for _, f := range UploadedFiles {
|
|
if purpose == f.Purpose {
|
|
listFiles.Data = append(listFiles.Data, f)
|
|
}
|
|
}
|
|
}
|
|
listFiles.Object = "list"
|
|
return c.Status(fiber.StatusOK).JSON(listFiles)
|
|
}
|
|
}
|
|
|
|
func getFileFromRequest(c *fiber.Ctx) (*schema.File, error) {
|
|
id := c.Params("file_id")
|
|
if id == "" {
|
|
return nil, fmt.Errorf("file_id parameter is required")
|
|
}
|
|
|
|
for _, f := range UploadedFiles {
|
|
if id == f.ID {
|
|
return &f, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("unable to find file id %s", id)
|
|
}
|
|
|
|
// GetFilesEndpoint is the OpenAI API endpoint to get files https://platform.openai.com/docs/api-reference/files/retrieve
|
|
// @Summary Returns information about a specific file.
|
|
// @Success 200 {object} schema.File "Response"
|
|
// @Router /v1/files/{file_id} [get]
|
|
func GetFilesEndpoint(cm *config.BackendConfigLoader, appConfig *config.ApplicationConfig) func(c *fiber.Ctx) error {
|
|
return func(c *fiber.Ctx) error {
|
|
file, err := getFileFromRequest(c)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).SendString(bluemonday.StrictPolicy().Sanitize(err.Error()))
|
|
}
|
|
|
|
return c.JSON(file)
|
|
}
|
|
}
|
|
|
|
type DeleteStatus struct {
|
|
Id string
|
|
Object string
|
|
Deleted bool
|
|
}
|
|
|
|
// DeleteFilesEndpoint is the OpenAI API endpoint to delete files https://platform.openai.com/docs/api-reference/files/delete
|
|
// @Summary Delete a file.
|
|
// @Success 200 {object} DeleteStatus "Response"
|
|
// @Router /v1/files/{file_id} [delete]
|
|
func DeleteFilesEndpoint(cm *config.BackendConfigLoader, appConfig *config.ApplicationConfig) func(c *fiber.Ctx) error {
|
|
|
|
return func(c *fiber.Ctx) error {
|
|
file, err := getFileFromRequest(c)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).SendString(bluemonday.StrictPolicy().Sanitize(err.Error()))
|
|
}
|
|
|
|
err = os.Remove(filepath.Join(appConfig.UploadDir, file.Filename))
|
|
if err != nil {
|
|
// If the file doesn't exist then we should just continue to remove it
|
|
if !errors.Is(err, os.ErrNotExist) {
|
|
return c.Status(fiber.StatusInternalServerError).SendString(bluemonday.StrictPolicy().Sanitize(fmt.Sprintf("Unable to delete file: %s, %v", file.Filename, err)))
|
|
}
|
|
}
|
|
|
|
// Remove upload from list
|
|
for i, f := range UploadedFiles {
|
|
if f.ID == file.ID {
|
|
UploadedFiles = append(UploadedFiles[:i], UploadedFiles[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
|
|
utils.SaveConfig(appConfig.UploadDir, UploadedFilesFile, UploadedFiles)
|
|
return c.JSON(DeleteStatus{
|
|
Id: file.ID,
|
|
Object: "file",
|
|
Deleted: true,
|
|
})
|
|
}
|
|
}
|
|
|
|
// GetFilesContentsEndpoint is the OpenAI API endpoint to get files content https://platform.openai.com/docs/api-reference/files/retrieve-contents
|
|
// @Summary Returns information about a specific file.
|
|
// @Success 200 {string} binary "file"
|
|
// @Router /v1/files/{file_id}/content [get]
|
|
// GetFilesContentsEndpoint
|
|
func GetFilesContentsEndpoint(cm *config.BackendConfigLoader, appConfig *config.ApplicationConfig) func(c *fiber.Ctx) error {
|
|
return func(c *fiber.Ctx) error {
|
|
file, err := getFileFromRequest(c)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).SendString(bluemonday.StrictPolicy().Sanitize(err.Error()))
|
|
}
|
|
|
|
fileContents, err := os.ReadFile(filepath.Join(appConfig.UploadDir, file.Filename))
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).SendString(bluemonday.StrictPolicy().Sanitize(err.Error()))
|
|
}
|
|
|
|
return c.Send(fileContents)
|
|
}
|
|
}
|