Honor requested image quality #382
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
@@ -38,7 +39,8 @@ func (g multimodalGateway) handler(operation capability.MultimodalOperation) htt
|
||||
http.Error(w, "local image generation capability unavailable", http.StatusBadGateway)
|
||||
return
|
||||
}
|
||||
image, err := g.imageGenerator.Generate(r.Context(), g.imageModel, r.FormValue("prompt"), r.FormValue("size"))
|
||||
prompt := r.FormValue("prompt")
|
||||
image, err := g.imageGenerator.Generate(r.Context(), g.imageModel, prompt, imageRequestSize(prompt, r.FormValue("size")))
|
||||
if err != nil || strings.TrimSpace(image.DataBase64) == "" {
|
||||
logMultimodalFailure(operation, err)
|
||||
http.Error(w, "local image generation capability unavailable", http.StatusBadGateway)
|
||||
@@ -96,6 +98,40 @@ func (g multimodalGateway) handler(operation capability.MultimodalOperation) htt
|
||||
}
|
||||
}
|
||||
|
||||
// imageRequestSize is a transport-level normalization for the local image
|
||||
// capability. An explicit, valid size always wins. When the caller only
|
||||
// expresses a conventional output-quality target, the capability translates it
|
||||
// to a supported provider size without exposing provider workflow details to
|
||||
// the interaction core. This policy is deliberately local and replaceable
|
||||
// with the image capability implementation.
|
||||
func imageRequestSize(prompt, requested string) string {
|
||||
if isImageSize(requested) {
|
||||
return strings.TrimSpace(requested)
|
||||
}
|
||||
words := strings.Fields(strings.ToLower(prompt))
|
||||
for index, word := range words {
|
||||
switch word {
|
||||
case "4k", "uhd":
|
||||
return "2048x2048"
|
||||
case "hd":
|
||||
return "1024x1024"
|
||||
case "ultra":
|
||||
if index+1 < len(words) && words[index+1] == "hd" {
|
||||
return "2048x2048"
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func isImageSize(value string) bool {
|
||||
var width, height int
|
||||
if _, err := fmt.Sscanf(strings.TrimSpace(value), "%dx%d", &width, &height); err != nil {
|
||||
return false
|
||||
}
|
||||
return width >= 256 && height >= 256 && width <= 2048 && height <= 2048
|
||||
}
|
||||
|
||||
func logMultimodalFailure(operation capability.MultimodalOperation, err error) {
|
||||
// Keep provider details in server diagnostics; never return them to chat.
|
||||
log.Printf("multimodal operation %s failed: %v", operation, err)
|
||||
|
||||
@@ -47,6 +47,27 @@ func TestMultimodalImageGenerationFailsClosedWhenSkillIsUnbound(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageRequestSizeUsesExplicitSizeOrQualityTarget(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
prompt string
|
||||
requested string
|
||||
want string
|
||||
}{
|
||||
{name: "explicit", prompt: "нарисуй птицу", requested: "768x512", want: "768x512"},
|
||||
{name: "hd", prompt: "нарисуй птицу в HD", want: "1024x1024"},
|
||||
{name: "uhd", prompt: "draw a bird in UHD", want: "2048x2048"},
|
||||
{name: "ordinary", prompt: "нарисуй птицу", want: ""},
|
||||
{name: "invalid explicit", prompt: "нарисуй птицу", requested: "100x100", want: ""},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if got := imageRequestSize(test.prompt, test.requested); got != test.want {
|
||||
t.Fatalf("imageRequestSize(%q, %q) = %q, want %q", test.prompt, test.requested, got, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultimodalVideoUnderstandingFailsClosedWhenSkillIsUnbound(t *testing.T) {
|
||||
server := multimodalGateway{now: time.Now}
|
||||
request := multipartRequest(t, "/v1/multimodal/video-understand", "clip.mp4", []byte("video"))
|
||||
|
||||
Reference in New Issue
Block a user