fix: 兼容像素分辨率参数

This commit is contained in:
wangbo 2026-06-08 23:21:14 +08:00
parent 97f29ed156
commit a8fa8dd212
3 changed files with 124 additions and 2 deletions

View File

@ -207,6 +207,14 @@ func (imageSizeProcessor) Process(params map[string]any, modelType string, conte
width, height = constrainImageDimensions(width, height, capability)
params["width"] = width
params["height"] = height
if stringFromAny(params["aspect_ratio"]) == "" {
aspectRatio := aspectRatioFromDimensions(width, height)
allowed := aspectRatioAllowed(capability["aspect_ratio_allowed"], firstNonEmptyString(stringFromAny(params["resolution"]), context.resolution))
if processed, ok := validateAndAdjustAspectRatio(aspectRatio, capability, allowed); ok && processed != "" {
params["aspect_ratio"] = processed
context.aspectRatio = processed
}
}
resolution := normalizeImageResolutionForCapability(firstNonEmptyString(stringFromAny(params["resolution"]), context.resolution), width, height, capability)
if resolution != "" {
params["resolution"] = resolution
@ -248,7 +256,10 @@ func imageDimensionsFromParams(params map[string]any) (int, int, bool) {
if width > 0 && height > 0 {
return width, height, true
}
return parsePixelSizeString(stringFromAny(params["size"]))
if width, height, ok := parsePixelSizeString(stringFromAny(params["size"])); ok {
return width, height, true
}
return parsePixelSizeString(stringFromAny(params["resolution"]))
}
func imageSizeCapabilityConfigured(capability map[string]any) bool {
@ -431,6 +442,30 @@ func imageResolutionFromDimensions(width int, height int) string {
}
}
func aspectRatioFromDimensions(width int, height int) string {
if width <= 0 || height <= 0 {
return ""
}
divisor := gcd(width, height)
return fmt.Sprintf("%d:%d", width/divisor, height/divisor)
}
func gcd(a int, b int) int {
if a < 0 {
a = -a
}
if b < 0 {
b = -b
}
for b != 0 {
a, b = b, a%b
}
if a == 0 {
return 1
}
return a
}
func closestImageResolution(target string, allowed []string) string {
order := []string{"1K", "2K", "3K", "4K", "8K"}
targetIndex := indexOfString(order, target)

View File

@ -1,6 +1,7 @@
package runner
import (
"fmt"
"testing"
"github.com/easyai/easyai-ai-gateway/apps/api/internal/store"
@ -699,6 +700,65 @@ func TestParamProcessorImageSizeConstraintsNormalizeExplicitDimensions(t *testin
t.Fatalf("expected image size preprocessing log against output_size_range, got %+v", result.Log.Changes)
}
func TestParamProcessorImageSizeConstraintsAcceptPixelResolutionStrings(t *testing.T) {
candidate := store.RuntimeModelCandidate{
ModelType: "image_generate",
Capabilities: map[string]any{
"image_generate": map[string]any{
"output_resolutions": []any{"1K", "2K", "4K"},
"aspect_ratio_allowed": []any{
"1:1",
"16:9",
"9:16",
},
"output_size_range": []any{655360, 8294400},
"width_height_range": []any{1, 3840},
},
},
}
for name, body := range map[string]map[string]any{
"resolution": {
"model": "gpt-image-2",
"prompt": "draw",
"resolution": "3840x2160",
},
"size": {
"model": "gpt-image-2",
"prompt": "draw",
"size": "3840x2160",
},
"non-standard-resolution": {
"model": "gpt-image-2",
"prompt": "draw",
"resolution": "3600x1900",
},
} {
t.Run(name, func(t *testing.T) {
processed := preprocessRequest("images.generations", body, candidate)
expectedWidth := 3840
expectedHeight := 2160
if name == "non-standard-resolution" {
expectedWidth = 3600
expectedHeight = 1900
}
if processed["width"] != expectedWidth || processed["height"] != expectedHeight {
t.Fatalf("pixel resolution string should populate width/height, got %+v", processed)
}
if processed["aspect_ratio"] != "16:9" {
t.Fatalf("pixel resolution string should infer aspect_ratio, got %+v", processed)
}
if processed["resolution"] != "4K" {
t.Fatalf("pixel resolution string should normalize resolution to allowed bucket, got %+v", processed)
}
expectedSize := fmt.Sprintf("%dx%d", expectedWidth, expectedHeight)
if processed["size"] != expectedSize {
t.Fatalf("size should stay synchronized with normalized width/height, got %+v", processed)
}
})
}
}
func TestParamProcessorImageSizeConstraintsNormalizeEditDimensions(t *testing.T) {
body := map[string]any{
"model": "gpt-image-2",

View File

@ -29,7 +29,7 @@ func validateAndAdjustAspectRatio(aspectRatio string, capability map[string]any,
if containsString(allowed, aspectRatio) {
return aspectRatio, true
}
return allowed[0], true
return closestAspectRatio(aspectRatio, allowed), true
}
func isMediaModelTypeWithAspectRatio(capability map[string]any) bool {
@ -445,6 +445,33 @@ func adjustAspectRatioToRange(value string, minValue float64, maxValue float64,
return ratioString(maxValue)
}
func closestAspectRatio(value string, allowed []string) string {
if len(allowed) == 0 {
return value
}
current, ok := aspectRatioNumber(value)
if !ok {
return allowed[0]
}
closest := ""
minDiff := math.Inf(1)
for _, candidate := range allowed {
ratio, ok := aspectRatioNumber(candidate)
if !ok {
continue
}
diff := math.Abs(ratio - current)
if diff < minDiff {
minDiff = diff
closest = candidate
}
}
if closest != "" {
return closest
}
return allowed[0]
}
func ratioString(value float64) string {
if value <= 0 {
return "1:1"