Revert "Gemini Veo3.1[AI Studio]增加图生视频支持"
This commit is contained in:
@@ -24,9 +24,13 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VideoGenerationConfig represents the video generation configuration
|
// ============================
|
||||||
|
// Request / Response structures
|
||||||
|
// ============================
|
||||||
|
|
||||||
|
// GeminiVideoGenerationConfig represents the video generation configuration
|
||||||
// Based on: https://ai.google.dev/gemini-api/docs/video
|
// Based on: https://ai.google.dev/gemini-api/docs/video
|
||||||
type VideoGenerationConfig struct {
|
type GeminiVideoGenerationConfig struct {
|
||||||
AspectRatio string `json:"aspectRatio,omitempty"` // "16:9" or "9:16"
|
AspectRatio string `json:"aspectRatio,omitempty"` // "16:9" or "9:16"
|
||||||
DurationSeconds float64 `json:"durationSeconds,omitempty"` // 4, 6, or 8 (as number)
|
DurationSeconds float64 `json:"durationSeconds,omitempty"` // 4, 6, or 8 (as number)
|
||||||
NegativePrompt string `json:"negativePrompt,omitempty"` // unwanted elements
|
NegativePrompt string `json:"negativePrompt,omitempty"` // unwanted elements
|
||||||
@@ -34,21 +38,15 @@ type VideoGenerationConfig struct {
|
|||||||
Resolution string `json:"resolution,omitempty"` // video resolution
|
Resolution string `json:"resolution,omitempty"` // video resolution
|
||||||
}
|
}
|
||||||
|
|
||||||
type Image struct {
|
// GeminiVideoRequest represents a single video generation instance
|
||||||
BytesBase64Encoded string `json:"bytesBase64Encoded,omitempty"`
|
type GeminiVideoRequest struct {
|
||||||
MimeType string `json:"mimeType,omitempty"`
|
Prompt string `json:"prompt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type VideoRequest struct {
|
// GeminiVideoPayload represents the complete video generation request payload
|
||||||
Prompt string `json:"prompt"`
|
type GeminiVideoPayload struct {
|
||||||
Image *Image `json:"image,omitempty"`
|
Instances []GeminiVideoRequest `json:"instances"`
|
||||||
LastFrame *Image `json:"lastFrame,omitempty"`
|
Parameters GeminiVideoGenerationConfig `json:"parameters,omitempty"`
|
||||||
}
|
|
||||||
|
|
||||||
// VideoPayload represents the complete video generation request payload
|
|
||||||
type VideoPayload struct {
|
|
||||||
Instances []VideoRequest `json:"instances"`
|
|
||||||
Parameters VideoGenerationConfig `json:"parameters,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type submitResponse struct {
|
type submitResponse struct {
|
||||||
@@ -77,8 +75,6 @@ type operationResponse struct {
|
|||||||
URI string `json:"uri"`
|
URI string `json:"uri"`
|
||||||
} `json:"video"`
|
} `json:"video"`
|
||||||
} `json:"generatedSamples"`
|
} `json:"generatedSamples"`
|
||||||
RaiMediaFilteredCount int `json:"raiMediaFilteredCount"`
|
|
||||||
RaiMediaFilteredReasons []string `json:"raiMediaFilteredReasons"`
|
|
||||||
} `json:"generateVideoResponse"`
|
} `json:"generateVideoResponse"`
|
||||||
} `json:"response"`
|
} `json:"response"`
|
||||||
Error struct {
|
Error struct {
|
||||||
@@ -104,7 +100,8 @@ func (a *TaskAdaptor) Init(info *relaycommon.RelayInfo) {
|
|||||||
|
|
||||||
// ValidateRequestAndSetAction parses body, validates fields and sets default action.
|
// ValidateRequestAndSetAction parses body, validates fields and sets default action.
|
||||||
func (a *TaskAdaptor) ValidateRequestAndSetAction(c *gin.Context, info *relaycommon.RelayInfo) (taskErr *dto.TaskError) {
|
func (a *TaskAdaptor) ValidateRequestAndSetAction(c *gin.Context, info *relaycommon.RelayInfo) (taskErr *dto.TaskError) {
|
||||||
return relaycommon.ValidateBasicTaskRequest(c, info, constant.TaskActionGenerate)
|
// Use the standard validation method for TaskSubmitReq
|
||||||
|
return relaycommon.ValidateBasicTaskRequest(c, info, constant.TaskActionTextGenerate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildRequestURL constructs the upstream URL.
|
// BuildRequestURL constructs the upstream URL.
|
||||||
@@ -140,21 +137,13 @@ func (a *TaskAdaptor) BuildRequestBody(c *gin.Context, info *relaycommon.RelayIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create structured video generation request
|
// Create structured video generation request
|
||||||
body := VideoPayload{
|
body := GeminiVideoPayload{
|
||||||
Instances: []VideoRequest{
|
Instances: []GeminiVideoRequest{
|
||||||
{Prompt: req.Prompt},
|
{Prompt: req.Prompt},
|
||||||
},
|
},
|
||||||
Parameters: VideoGenerationConfig{},
|
Parameters: GeminiVideoGenerationConfig{},
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(req.Images) > 0 {
|
|
||||||
body.Instances[0].Image = a.convertImage(req.Images[0])
|
|
||||||
}
|
|
||||||
if len(req.Images) > 1 {
|
|
||||||
body.Instances[0].LastFrame = a.convertImage(req.Images[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse metadata for additional configuration
|
|
||||||
metadata := req.Metadata
|
metadata := req.Metadata
|
||||||
medaBytes, err := json.Marshal(metadata)
|
medaBytes, err := json.Marshal(metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -258,19 +247,20 @@ func (a *TaskAdaptor) ParseTaskResult(respBody []byte) (*relaycommon.TaskInfo, e
|
|||||||
return ti, nil
|
return ti, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(op.Response.GenerateVideoResponse.GeneratedSamples) == 0 {
|
ti.Status = model.TaskStatusSuccess
|
||||||
ti.Status = model.TaskStatusFailure
|
|
||||||
ti.Reason = fmt.Sprintf("no generated video url found: %s", strings.Join(op.Response.GenerateVideoResponse.RaiMediaFilteredReasons, "; "))
|
|
||||||
} else {
|
|
||||||
if uri := op.Response.GenerateVideoResponse.GeneratedSamples[0].Video.URI; uri != "" {
|
|
||||||
ti.RemoteUrl = uri
|
|
||||||
}
|
|
||||||
ti.Status = model.TaskStatusSuccess
|
|
||||||
}
|
|
||||||
ti.Progress = "100%"
|
ti.Progress = "100%"
|
||||||
|
|
||||||
taskID := encodeLocalTaskID(op.Name)
|
taskID := encodeLocalTaskID(op.Name)
|
||||||
ti.TaskID = taskID
|
ti.TaskID = taskID
|
||||||
ti.Url = fmt.Sprintf("%s/v1/videos/%s/content", system_setting.ServerAddress, taskID)
|
ti.Url = fmt.Sprintf("%s/v1/videos/%s/content", system_setting.ServerAddress, taskID)
|
||||||
|
|
||||||
|
// Extract URL from generateVideoResponse if available
|
||||||
|
if len(op.Response.GenerateVideoResponse.GeneratedSamples) > 0 {
|
||||||
|
if uri := op.Response.GenerateVideoResponse.GeneratedSamples[0].Video.URI; uri != "" {
|
||||||
|
ti.RemoteUrl = uri
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ti, nil
|
return ti, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,30 +289,6 @@ func (a *TaskAdaptor) ConvertToOpenAIVideo(task *model.Task) ([]byte, error) {
|
|||||||
return common.Marshal(video)
|
return common.Marshal(video)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *TaskAdaptor) convertImage(imageStr string) *Image {
|
|
||||||
if strings.TrimSpace(imageStr) == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
img := &Image{
|
|
||||||
MimeType: "image/png",
|
|
||||||
BytesBase64Encoded: imageStr,
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(imageStr, "data:image/") {
|
|
||||||
parts := strings.Split(imageStr, ";base64,")
|
|
||||||
if len(parts) == 2 {
|
|
||||||
img.MimeType = strings.TrimPrefix(parts[0], "data:")
|
|
||||||
img.BytesBase64Encoded = parts[1]
|
|
||||||
}
|
|
||||||
} else if strings.HasPrefix(imageStr, "http") {
|
|
||||||
mimeType, data, err := service.GetImageFromUrl(imageStr)
|
|
||||||
if err == nil {
|
|
||||||
img.MimeType = mimeType
|
|
||||||
img.BytesBase64Encoded = data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return img
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================
|
// ============================
|
||||||
// helpers
|
// helpers
|
||||||
// ============================
|
// ============================
|
||||||
|
|||||||
Reference in New Issue
Block a user