Spaces:
Configuration error
Configuration error
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) | |
} | |
} | |