-
Notifications
You must be signed in to change notification settings - Fork 11.2k
fix: align Vertex content fetch flow with Gemini and handle base64 #3038
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -145,6 +145,134 @@ func extractGeminiVideoURLFromGeneratedSamples(gvr map[string]any) string { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func getVertexVideoURL(channel *model.Channel, task *model.Task) (string, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if channel == nil || task == nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "", fmt.Errorf("invalid channel or task") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if url := strings.TrimSpace(task.GetResultURL()); url != "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return url, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if url := extractVertexVideoURLFromTaskData(task); url != "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return url, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| baseURL := constant.ChannelBaseURLs[channel.Type] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if channel.GetBaseURL() != "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| baseURL = channel.GetBaseURL() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| adaptor := relay.GetTaskAdaptor(constant.TaskPlatform(strconv.Itoa(channel.Type))) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if adaptor == nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "", fmt.Errorf("vertex task adaptor not found") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key := getVertexTaskKey(channel, task) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if key == "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "", fmt.Errorf("vertex key not available for task") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| resp, err := adaptor.FetchTask(baseURL, key, map[string]any{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "task_id": task.GetUpstreamTaskID(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "action": task.Action, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, channel.GetSetting().Proxy) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "", fmt.Errorf("fetch task failed: %w", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defer resp.Body.Close() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body, err := io.ReadAll(resp.Body) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "", fmt.Errorf("read task response failed: %w", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| taskInfo, parseErr := adaptor.ParseTaskResult(body) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if parseErr == nil && taskInfo != nil && strings.TrimSpace(taskInfo.Url) != "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return taskInfo.Url, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+189
to
+190
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Return the trimmed URL after validation. You validate 💡 Proposed fix- if parseErr == nil && taskInfo != nil && strings.TrimSpace(taskInfo.Url) != "" {
- return taskInfo.Url, nil
+ if parseErr == nil && taskInfo != nil && strings.TrimSpace(taskInfo.Url) != "" {
+ return strings.TrimSpace(taskInfo.Url), nil
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if url := extractVertexVideoURLFromPayload(body); url != "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return url, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if parseErr != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "", fmt.Errorf("parse task result failed: %w", parseErr) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "", fmt.Errorf("vertex video url not found") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func getVertexTaskKey(channel *model.Channel, task *model.Task) string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if task != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if key := strings.TrimSpace(task.PrivateData.Key); key != "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return key | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if channel == nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| keys := channel.GetKeys() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, key := range keys { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key = strings.TrimSpace(key) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if key != "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return key | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return strings.TrimSpace(channel.Key) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func extractVertexVideoURLFromTaskData(task *model.Task) string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if task == nil || len(task.Data) == 0 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return extractVertexVideoURLFromPayload(task.Data) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func extractVertexVideoURLFromPayload(body []byte) string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var payload map[string]any | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err := common.Unmarshal(body, &payload); err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| resp, ok := payload["response"].(map[string]any) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if !ok || resp == nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if videos, ok := resp["videos"].([]any); ok && len(videos) > 0 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if video, ok := videos[0].(map[string]any); ok && video != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if b64, _ := video["bytesBase64Encoded"].(string); strings.TrimSpace(b64) != "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mime, _ := video["mimeType"].(string) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| enc, _ := video["encoding"].(string) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return buildVideoDataURL(mime, enc, b64) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+237
to
+244
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The logic only checks 💡 Proposed fix- if videos, ok := resp["videos"].([]any); ok && len(videos) > 0 {
- if video, ok := videos[0].(map[string]any); ok && video != nil {
- if b64, _ := video["bytesBase64Encoded"].(string); strings.TrimSpace(b64) != "" {
- mime, _ := video["mimeType"].(string)
- enc, _ := video["encoding"].(string)
- return buildVideoDataURL(mime, enc, b64)
- }
- }
- }
+ if videos, ok := resp["videos"].([]any); ok {
+ for _, item := range videos {
+ video, ok := item.(map[string]any)
+ if !ok || video == nil {
+ continue
+ }
+ if uri, _ := video["uri"].(string); strings.TrimSpace(uri) != "" {
+ return strings.TrimSpace(uri)
+ }
+ if b64, _ := video["bytesBase64Encoded"].(string); strings.TrimSpace(b64) != "" {
+ mime, _ := video["mimeType"].(string)
+ enc, _ := video["encoding"].(string)
+ return buildVideoDataURL(mime, enc, b64)
+ }
+ }
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if b64, _ := resp["bytesBase64Encoded"].(string); strings.TrimSpace(b64) != "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| enc, _ := resp["encoding"].(string) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return buildVideoDataURL("", enc, b64) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if video, _ := resp["video"].(string); strings.TrimSpace(video) != "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if strings.HasPrefix(video, "data:") || strings.HasPrefix(video, "http://") || strings.HasPrefix(video, "https://") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return video | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| enc, _ := resp["encoding"].(string) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return buildVideoDataURL("", enc, video) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+250
to
+255
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Normalize Whitespace is stripped for emptiness only; scheme checks and return values should use the trimmed value too. 💡 Proposed fix- if video, _ := resp["video"].(string); strings.TrimSpace(video) != "" {
- if strings.HasPrefix(video, "data:") || strings.HasPrefix(video, "http://") || strings.HasPrefix(video, "https://") {
- return video
+ if video, _ := resp["video"].(string); strings.TrimSpace(video) != "" {
+ trimmedVideo := strings.TrimSpace(video)
+ if strings.HasPrefix(trimmedVideo, "data:") || strings.HasPrefix(trimmedVideo, "http://") || strings.HasPrefix(trimmedVideo, "https://") {
+ return trimmedVideo
}
enc, _ := resp["encoding"].(string)
- return buildVideoDataURL("", enc, video)
+ return buildVideoDataURL("", enc, trimmedVideo)
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func buildVideoDataURL(mimeType string, encoding string, base64Data string) string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mime := strings.TrimSpace(mimeType) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if mime == "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| enc := strings.TrimSpace(encoding) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if enc == "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| enc = "mp4" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if strings.Contains(enc, "/") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mime = enc | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mime = "video/" + enc | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+260
to
+271
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not infer MIME as When 💡 Proposed fix func buildVideoDataURL(mimeType string, encoding string, base64Data string) string {
mime := strings.TrimSpace(mimeType)
if mime == "" {
- enc := strings.TrimSpace(encoding)
- if enc == "" {
- enc = "mp4"
- }
- if strings.Contains(enc, "/") {
- mime = enc
- } else {
- mime = "video/" + enc
- }
+ enc := strings.ToLower(strings.TrimSpace(encoding))
+ switch enc {
+ case "", "base64":
+ mime = "video/mp4"
+ default:
+ if strings.Contains(enc, "/") {
+ mime = enc
+ } else {
+ mime = "video/" + enc
+ }
+ }
}
return "data:" + mime + ";base64," + base64Data
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "data:" + mime + ";base64," + base64Data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func ensureAPIKey(uri, key string) string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if key == "" || uri == "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return uri | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard decoded payload size before allocating full video bytes.
writeVideoDataURLcurrently decodes the whole base64 payload into memory. Large inline videos can cause high memory pressure or OOM under concurrency.💡 Proposed fix
func writeVideoDataURL(c *gin.Context, dataURL string) error { + const maxInlineVideoBytes = 64 << 20 // 64 MiB decoded payload cap parts := strings.SplitN(dataURL, ",", 2) if len(parts) != 2 { return fmt.Errorf("invalid data url") } @@ mimeType := strings.TrimPrefix(header, "data:") mimeType = strings.TrimSuffix(mimeType, ";base64") if mimeType == "" { mimeType = "video/mp4" } + + if base64.StdEncoding.DecodedLen(len(payload)) > maxInlineVideoBytes { + return fmt.Errorf("data url payload too large") + } videoBytes, err := base64.StdEncoding.DecodeString(payload) if err != nil { videoBytes, err = base64.RawStdEncoding.DecodeString(payload) if err != nil { return err } }📝 Committable suggestion
🤖 Prompt for AI Agents