fix(apicompat): skip empty base64 image URLs
This commit is contained in:
@@ -181,6 +181,50 @@ func TestChatCompletionsToResponses_ImageURL(t *testing.T) {
|
|||||||
assert.Equal(t, "data:image/png;base64,abc123", parts[1].ImageURL)
|
assert.Equal(t, "data:image/png;base64,abc123", parts[1].ImageURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestChatCompletionsToResponses_EmptyBase64ImageURLSkipped(t *testing.T) {
|
||||||
|
content := `[{"type":"text","text":"Describe this"},{"type":"image_url","image_url":{"url":"data:image/png;base64,"}}]`
|
||||||
|
req := &ChatCompletionsRequest{
|
||||||
|
Model: "gpt-4o",
|
||||||
|
Messages: []ChatMessage{
|
||||||
|
{Role: "user", Content: json.RawMessage(content)},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resp, err := ChatCompletionsToResponses(req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var items []ResponsesInputItem
|
||||||
|
require.NoError(t, json.Unmarshal(resp.Input, &items))
|
||||||
|
require.Len(t, items, 1)
|
||||||
|
|
||||||
|
var parts []ResponsesContentPart
|
||||||
|
require.NoError(t, json.Unmarshal(items[0].Content, &parts))
|
||||||
|
require.Len(t, parts, 1)
|
||||||
|
assert.Equal(t, "input_text", parts[0].Type)
|
||||||
|
assert.Equal(t, "Describe this", parts[0].Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChatCompletionsToResponses_WhitespaceOnlyBase64ImageURLSkipped(t *testing.T) {
|
||||||
|
content := `[{"type":"text","text":"Describe this"},{"type":"image_url","image_url":{"url":"data:image/png;base64, "}}]`
|
||||||
|
req := &ChatCompletionsRequest{
|
||||||
|
Model: "gpt-4o",
|
||||||
|
Messages: []ChatMessage{
|
||||||
|
{Role: "user", Content: json.RawMessage(content)},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resp, err := ChatCompletionsToResponses(req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var items []ResponsesInputItem
|
||||||
|
require.NoError(t, json.Unmarshal(resp.Input, &items))
|
||||||
|
require.Len(t, items, 1)
|
||||||
|
|
||||||
|
var parts []ResponsesContentPart
|
||||||
|
require.NoError(t, json.Unmarshal(items[0].Content, &parts))
|
||||||
|
require.Len(t, parts, 1)
|
||||||
|
assert.Equal(t, "input_text", parts[0].Type)
|
||||||
|
assert.Equal(t, "Describe this", parts[0].Text)
|
||||||
|
}
|
||||||
|
|
||||||
func TestChatCompletionsToResponses_SystemArrayContent(t *testing.T) {
|
func TestChatCompletionsToResponses_SystemArrayContent(t *testing.T) {
|
||||||
req := &ChatCompletionsRequest{
|
req := &ChatCompletionsRequest{
|
||||||
Model: "gpt-4o",
|
Model: "gpt-4o",
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ func convertChatContentPartsToResponses(parts []ChatContentPart) []ResponsesCont
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
case "image_url":
|
case "image_url":
|
||||||
if p.ImageURL != nil && p.ImageURL.URL != "" {
|
if p.ImageURL != nil && p.ImageURL.URL != "" && !isEmptyBase64DataURI(p.ImageURL.URL) {
|
||||||
responseParts = append(responseParts, ResponsesContentPart{
|
responseParts = append(responseParts, ResponsesContentPart{
|
||||||
Type: "input_image",
|
Type: "input_image",
|
||||||
ImageURL: p.ImageURL.URL,
|
ImageURL: p.ImageURL.URL,
|
||||||
@@ -350,6 +350,22 @@ func convertChatContentPartsToResponses(parts []ChatContentPart) []ResponsesCont
|
|||||||
return responseParts
|
return responseParts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isEmptyBase64DataURI(raw string) bool {
|
||||||
|
if !strings.HasPrefix(raw, "data:") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
rest := strings.TrimPrefix(raw, "data:")
|
||||||
|
semicolonIdx := strings.Index(rest, ";")
|
||||||
|
if semicolonIdx < 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
rest = rest[semicolonIdx+1:]
|
||||||
|
if !strings.HasPrefix(rest, "base64,") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(strings.TrimPrefix(rest, "base64,")) == ""
|
||||||
|
}
|
||||||
|
|
||||||
func flattenChatContentParts(parts []ChatContentPart) string {
|
func flattenChatContentParts(parts []ChatContentPart) string {
|
||||||
var textParts []string
|
var textParts []string
|
||||||
for _, p := range parts {
|
for _, p := range parts {
|
||||||
|
|||||||
Reference in New Issue
Block a user