feat(gemini): implement video generation configuration and billing estimation
- Added Gemini video generation configuration structures and payloads. - Introduced functions for parsing and resolving video duration and resolution from metadata. - Enhanced the Vertex adaptor to support Gemini video generation requests and billing estimation based on duration and resolution. - Updated model pricing settings for new Gemini video models.
This commit is contained in:
100
relay/channel/task/gemini/image.go
Normal file
100
relay/channel/task/gemini/image.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package gemini
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/QuantumNous/new-api/constant"
|
||||
relaycommon "github.com/QuantumNous/new-api/relay/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const maxVeoImageSize = 20 * 1024 * 1024 // 20 MB
|
||||
|
||||
// ExtractMultipartImage reads the first `input_reference` file from a multipart
|
||||
// form upload and returns a VeoImageInput. Returns nil if no file is present.
|
||||
func ExtractMultipartImage(c *gin.Context, info *relaycommon.RelayInfo) *VeoImageInput {
|
||||
mf, err := c.MultipartForm()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
files, exists := mf.File["input_reference"]
|
||||
if !exists || len(files) == 0 {
|
||||
return nil
|
||||
}
|
||||
fh := files[0]
|
||||
if fh.Size > maxVeoImageSize {
|
||||
return nil
|
||||
}
|
||||
file, err := fh.Open()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
fileBytes, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
mimeType := fh.Header.Get("Content-Type")
|
||||
if mimeType == "" || mimeType == "application/octet-stream" {
|
||||
mimeType = http.DetectContentType(fileBytes)
|
||||
}
|
||||
|
||||
info.Action = constant.TaskActionGenerate
|
||||
return &VeoImageInput{
|
||||
BytesBase64Encoded: base64.StdEncoding.EncodeToString(fileBytes),
|
||||
MimeType: mimeType,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseImageInput parses an image string (data URI or raw base64) into a
|
||||
// VeoImageInput. Returns nil if the input is empty or invalid.
|
||||
// TODO: support downloading HTTP URL images and converting to base64
|
||||
func ParseImageInput(imageStr string) *VeoImageInput {
|
||||
imageStr = strings.TrimSpace(imageStr)
|
||||
if imageStr == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if strings.HasPrefix(imageStr, "data:") {
|
||||
return parseDataURI(imageStr)
|
||||
}
|
||||
|
||||
raw, err := base64.StdEncoding.DecodeString(imageStr)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &VeoImageInput{
|
||||
BytesBase64Encoded: imageStr,
|
||||
MimeType: http.DetectContentType(raw),
|
||||
}
|
||||
}
|
||||
|
||||
func parseDataURI(uri string) *VeoImageInput {
|
||||
// data:image/png;base64,iVBOR...
|
||||
rest := uri[len("data:"):]
|
||||
idx := strings.Index(rest, ",")
|
||||
if idx < 0 {
|
||||
return nil
|
||||
}
|
||||
meta := rest[:idx]
|
||||
b64 := rest[idx+1:]
|
||||
if b64 == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
mimeType := "application/octet-stream"
|
||||
parts := strings.SplitN(meta, ";", 2)
|
||||
if len(parts) >= 1 && parts[0] != "" {
|
||||
mimeType = parts[0]
|
||||
}
|
||||
|
||||
return &VeoImageInput{
|
||||
BytesBase64Encoded: b64,
|
||||
MimeType: mimeType,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user