image.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package gemini
  2. import (
  3. "encoding/base64"
  4. "io"
  5. "net/http"
  6. "strings"
  7. "github.com/QuantumNous/new-api/constant"
  8. relaycommon "github.com/QuantumNous/new-api/relay/common"
  9. "github.com/gin-gonic/gin"
  10. )
  11. const maxVeoImageSize = 20 * 1024 * 1024 // 20 MB
  12. // ExtractMultipartImage reads the first `input_reference` file from a multipart
  13. // form upload and returns a VeoImageInput. Returns nil if no file is present.
  14. func ExtractMultipartImage(c *gin.Context, info *relaycommon.RelayInfo) *VeoImageInput {
  15. mf, err := c.MultipartForm()
  16. if err != nil {
  17. return nil
  18. }
  19. files, exists := mf.File["input_reference"]
  20. if !exists || len(files) == 0 {
  21. return nil
  22. }
  23. fh := files[0]
  24. if fh.Size > maxVeoImageSize {
  25. return nil
  26. }
  27. file, err := fh.Open()
  28. if err != nil {
  29. return nil
  30. }
  31. defer file.Close()
  32. fileBytes, err := io.ReadAll(file)
  33. if err != nil {
  34. return nil
  35. }
  36. mimeType := fh.Header.Get("Content-Type")
  37. if mimeType == "" || mimeType == "application/octet-stream" {
  38. mimeType = http.DetectContentType(fileBytes)
  39. }
  40. info.Action = constant.TaskActionGenerate
  41. return &VeoImageInput{
  42. BytesBase64Encoded: base64.StdEncoding.EncodeToString(fileBytes),
  43. MimeType: mimeType,
  44. }
  45. }
  46. // ParseImageInput parses an image string (data URI or raw base64) into a
  47. // VeoImageInput. Returns nil if the input is empty or invalid.
  48. // TODO: support downloading HTTP URL images and converting to base64
  49. func ParseImageInput(imageStr string) *VeoImageInput {
  50. imageStr = strings.TrimSpace(imageStr)
  51. if imageStr == "" {
  52. return nil
  53. }
  54. if strings.HasPrefix(imageStr, "data:") {
  55. return parseDataURI(imageStr)
  56. }
  57. raw, err := base64.StdEncoding.DecodeString(imageStr)
  58. if err != nil {
  59. return nil
  60. }
  61. return &VeoImageInput{
  62. BytesBase64Encoded: imageStr,
  63. MimeType: http.DetectContentType(raw),
  64. }
  65. }
  66. func parseDataURI(uri string) *VeoImageInput {
  67. // data:image/png;base64,iVBOR...
  68. rest := uri[len("data:"):]
  69. idx := strings.Index(rest, ",")
  70. if idx < 0 {
  71. return nil
  72. }
  73. meta := rest[:idx]
  74. b64 := rest[idx+1:]
  75. if b64 == "" {
  76. return nil
  77. }
  78. mimeType := "application/octet-stream"
  79. parts := strings.SplitN(meta, ";", 2)
  80. if len(parts) >= 1 && parts[0] != "" {
  81. mimeType = parts[0]
  82. }
  83. return &VeoImageInput{
  84. BytesBase64Encoded: b64,
  85. MimeType: mimeType,
  86. }
  87. }