fix(images): 规范 OpenAI 图像尺寸参数
This commit is contained in:
@@ -370,10 +370,14 @@ func TestOpenAIClientImageEditUsesMultipartWithMultipleImages(t *testing.T) {
|
||||
ModelType: "image_edit",
|
||||
Model: "gpt-image-2",
|
||||
Body: map[string]any{
|
||||
"model": "gpt-image-2",
|
||||
"prompt": "combine the references",
|
||||
"size": "1024x1536",
|
||||
"quality": "medium",
|
||||
"model": "gpt-image-2",
|
||||
"prompt": "combine the references",
|
||||
"size": "1024x1536",
|
||||
"quality": "medium",
|
||||
"aspect_ratio": "2:3",
|
||||
"resolution": "2K",
|
||||
"width": 1024,
|
||||
"height": 1536,
|
||||
"images": []any{
|
||||
"data:image/png;base64," + base64.StdEncoding.EncodeToString([]byte("image one")),
|
||||
"data:image/jpeg;base64," + base64.StdEncoding.EncodeToString([]byte("image two")),
|
||||
@@ -406,6 +410,62 @@ func TestOpenAIClientImageEditUsesMultipartWithMultipleImages(t *testing.T) {
|
||||
if _, ok := receivedFields["_metadata"]; ok {
|
||||
t.Fatalf("internal metadata must not be forwarded: %+v", receivedFields)
|
||||
}
|
||||
for _, field := range []string{"aspect_ratio", "resolution", "width", "height"} {
|
||||
if _, ok := receivedFields[field]; ok {
|
||||
t.Fatalf("generic image geometry field %q must not be forwarded: %+v", field, receivedFields)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenAIClientImageGenerationUsesSizeWithoutGenericGeometryFields(t *testing.T) {
|
||||
var received map[string]any
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := json.NewDecoder(r.Body).Decode(&received); err != nil {
|
||||
t.Fatalf("decode image generation body: %v", err)
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
||||
"data": []any{map[string]any{"b64_json": "aW1hZ2U="}},
|
||||
})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
_, err := (OpenAIClient{HTTPClient: server.Client()}).Run(context.Background(), Request{
|
||||
Kind: "images.generations",
|
||||
ModelType: "image_generate",
|
||||
Model: "gpt-image-2",
|
||||
Body: map[string]any{
|
||||
"model": "gpt-image-2",
|
||||
"prompt": "draw",
|
||||
"size": "2048x1152",
|
||||
"quality": "high",
|
||||
"aspect_ratio": "16:9",
|
||||
"aspectRatio": "16:9",
|
||||
"resolution": "2K",
|
||||
"width": 2048,
|
||||
"height": 1152,
|
||||
},
|
||||
Candidate: store.RuntimeModelCandidate{
|
||||
BaseURL: server.URL,
|
||||
Provider: "openai",
|
||||
ProviderModelName: "gpt-image-2-vip",
|
||||
ModelType: "image_generate",
|
||||
Credentials: map[string]any{"apiKey": "openai-key"},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("run OpenAI image generation: %v", err)
|
||||
}
|
||||
if received["model"] != "gpt-image-2-vip" ||
|
||||
received["prompt"] != "draw" ||
|
||||
received["size"] != "2048x1152" ||
|
||||
received["quality"] != "high" {
|
||||
t.Fatalf("unexpected image generation fields: %+v", received)
|
||||
}
|
||||
for _, field := range []string{"aspect_ratio", "aspectRatio", "resolution", "width", "height"} {
|
||||
if _, ok := received[field]; ok {
|
||||
t.Fatalf("generic image geometry field %q must not be forwarded: %+v", field, received)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenAIClientChatReasoningParamsByProvider(t *testing.T) {
|
||||
|
||||
@@ -65,6 +65,7 @@ func (c OpenAIClient) Run(ctx context.Context, request Request) (Response, error
|
||||
}
|
||||
}
|
||||
body["model"] = upstreamModelName(request.Candidate)
|
||||
normalizeOpenAIImageRequestBody(endpointKind, body)
|
||||
stream := openAIEndpointSupportsStream(endpointKind) && (request.Stream || boolValue(body, "stream"))
|
||||
ensureOpenAIStreamUsage(body, endpointKind, stream)
|
||||
raw, contentType, err := openAIRequestPayload(endpointKind, body, request.Candidate)
|
||||
@@ -171,6 +172,24 @@ func (c OpenAIClient) Run(ctx context.Context, request Request) (Response, error
|
||||
}, nil
|
||||
}
|
||||
|
||||
func normalizeOpenAIImageRequestBody(endpointKind string, body map[string]any) {
|
||||
if endpointKind != "images.generations" && endpointKind != "images.edits" {
|
||||
return
|
||||
}
|
||||
// OpenAI image endpoints express output geometry through size. The Gateway
|
||||
// keeps the generic fields for capability validation and billing, but they
|
||||
// are not valid OpenAI wire parameters.
|
||||
for _, key := range []string{
|
||||
"aspect_ratio",
|
||||
"aspectRatio",
|
||||
"resolution",
|
||||
"width",
|
||||
"height",
|
||||
} {
|
||||
delete(body, key)
|
||||
}
|
||||
}
|
||||
|
||||
func openAIRequestPayload(endpointKind string, body map[string]any, candidate store.RuntimeModelCandidate) ([]byte, string, error) {
|
||||
if endpointKind != "images.edits" {
|
||||
raw, err := json.Marshal(body)
|
||||
|
||||
Reference in New Issue
Block a user