feat(gateway): add Seedream 5.0 Pro

This commit is contained in:
2026-07-13 12:53:48 +08:00
parent 03abc0eab7
commit 9c300de72c
8 changed files with 460 additions and 5 deletions
+114
View File
@@ -4,6 +4,7 @@ import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
@@ -1673,6 +1674,119 @@ func TestVolcesClientImageEditPreservesExplicitSequentialDisabledAndClampsMaxIma
}
}
func TestVolcesClientSeedreamProGenerationUsesRealModelAndSingleOutput(t *testing.T) {
var captured map[string]any
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := json.NewDecoder(r.Body).Decode(&captured); err != nil {
t.Fatalf("decode request: %v", err)
}
_ = json.NewEncoder(w).Encode(map[string]any{
"id": "img-seedream-pro",
"data": []any{map[string]any{"url": "https://example.com/out.png"}},
})
}))
defer server.Close()
_, err := (VolcesClient{HTTPClient: server.Client()}).Run(context.Background(), Request{
Kind: "images.generations",
ModelType: "image_generate",
Model: "Seedream-5.0-Pro",
Body: map[string]any{
"model": "Seedream-5.0-Pro",
"prompt": "draw a mountain",
"resolution": "2K",
"n": 4,
"sequential_image_generation": "auto",
"sequential_image_generation_options": map[string]any{"max_images": 4},
},
Candidate: store.RuntimeModelCandidate{
BaseURL: server.URL,
ModelName: "Seedream-5.0-Pro",
ModelAlias: "Seedream-5.0-Pro",
ProviderModelName: "doubao-seedream-5-0-pro-260628",
Credentials: map[string]any{"apiKey": "volces-key"},
Capabilities: map[string]any{
"image_generate": map[string]any{
"output_multiple_images": false,
"output_max_images_count": 1,
},
},
},
})
if err != nil {
t.Fatalf("run Seedream Pro generation: %v", err)
}
if captured["model"] != "doubao-seedream-5-0-pro-260628" || captured["size"] != "2K" {
t.Fatalf("Seedream Pro should use the real model and resolution size, got %+v", captured)
}
if captured["n"] != float64(1) {
t.Fatalf("Seedream Pro should force single-image output, got %+v", captured)
}
if _, ok := captured["sequential_image_generation"]; ok {
t.Fatalf("Seedream Pro request must not include sequential image generation, got %+v", captured)
}
if _, ok := captured["sequential_image_generation_options"]; ok {
t.Fatalf("Seedream Pro request must not include sequential image options, got %+v", captured)
}
}
func TestVolcesClientSeedreamProEditForwardsTenReferencesAndCustomSize(t *testing.T) {
var captured map[string]any
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := json.NewDecoder(r.Body).Decode(&captured); err != nil {
t.Fatalf("decode request: %v", err)
}
_ = json.NewEncoder(w).Encode(map[string]any{
"id": "img-seedream-pro-edit",
"data": []any{map[string]any{"url": "https://example.com/out.png"}},
})
}))
defer server.Close()
images := make([]any, 10)
for index := range images {
images[index] = fmt.Sprintf("https://example.com/reference-%d.png", index+1)
}
_, err := (VolcesClient{HTTPClient: server.Client()}).Run(context.Background(), Request{
Kind: "images.edits",
ModelType: "image_edit",
Model: "Seedream-5.0-Pro",
Body: map[string]any{
"model": "Seedream-5.0-Pro",
"prompt": "combine the references",
"image": images,
"width": 1600,
"height": 900,
},
Candidate: store.RuntimeModelCandidate{
BaseURL: server.URL,
ModelName: "Seedream-5.0-Pro",
ModelAlias: "Seedream-5.0-Pro",
ProviderModelName: "doubao-seedream-5-0-pro-260628",
Credentials: map[string]any{"apiKey": "volces-key"},
Capabilities: map[string]any{
"image_edit": map[string]any{
"input_multiple_images": true,
"input_max_images_count": 10,
"output_multiple_images": false,
"output_max_images_count": 1,
"input_max_file_size_bytes": 30 * 1024 * 1024,
},
},
},
})
if err != nil {
t.Fatalf("run Seedream Pro edit: %v", err)
}
gotImages, _ := captured["image"].([]any)
if captured["model"] != "doubao-seedream-5-0-pro-260628" || captured["size"] != "1600x900" || len(gotImages) != 10 {
t.Fatalf("Seedream Pro edit should preserve ten references and custom size, got %+v", captured)
}
if _, ok := captured["sequential_image_generation"]; ok {
t.Fatalf("Seedream Pro edit must not include sequential image generation, got %+v", captured)
}
}
func TestVolcesClientVideoSubmitsAndPollsTask(t *testing.T) {
var submitPath string
var pollPath string
+11 -3
View File
@@ -781,14 +781,22 @@ func supportsMultipleOutputs(request Request, capabilityName string) bool {
}
func normalizeVolcesSequentialImageGeneration(body map[string]any, request Request) {
if !supportsMultipleOutputs(request, request.ModelType) {
delete(body, "sequential_image_generation")
delete(body, "sequential_image_generation_options")
if numericValue(body["n"], 1) > 1 {
body["n"] = 1
}
if numericValue(body["batch_size"], 1) > 1 {
body["batch_size"] = 1
}
return
}
options, hasOptions := volcesSequentialImageGenerationOptions(body)
normalizeVolcesSequentialMaxImages(options, request)
if _, explicit := body["sequential_image_generation"]; explicit {
return
}
if !supportsMultipleOutputs(request, request.ModelType) {
return
}
count := requestedVolcesSequentialImageCount(body, options)
if count <= 1 {
return