mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-19 12:50:51 +08:00
fix(openai): add index field to image response for LiteLLM compatibility
LiteLLM's Pydantic model requires an index field in each image object. Without it, responses fail validation with "images.0.index Field required".
This commit is contained in:
@@ -8,6 +8,7 @@ package chat_completions
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -181,14 +182,23 @@ func ConvertAntigravityResponseToOpenAI(_ context.Context, _ string, originalReq
|
|||||||
mimeType = "image/png"
|
mimeType = "image/png"
|
||||||
}
|
}
|
||||||
imageURL := fmt.Sprintf("data:%s;base64,%s", mimeType, data)
|
imageURL := fmt.Sprintf("data:%s;base64,%s", mimeType, data)
|
||||||
imagePayload := `{"image_url":{"url":""},"type":"image_url"}`
|
|
||||||
imagePayload, _ = sjson.Set(imagePayload, "image_url.url", imageURL)
|
|
||||||
imagesResult := gjson.Get(template, "choices.0.delta.images")
|
imagesResult := gjson.Get(template, "choices.0.delta.images")
|
||||||
if !imagesResult.Exists() || !imagesResult.IsArray() {
|
if !imagesResult.Exists() || !imagesResult.IsArray() {
|
||||||
template, _ = sjson.SetRaw(template, "choices.0.delta.images", `[]`)
|
template, _ = sjson.SetRaw(template, "choices.0.delta.images", `[]`)
|
||||||
}
|
}
|
||||||
|
imageIndex := len(gjson.Get(template, "choices.0.delta.images").Array())
|
||||||
|
imagePayload, err := json.Marshal(map[string]any{
|
||||||
|
"index": imageIndex,
|
||||||
|
"type": "image_url",
|
||||||
|
"image_url": map[string]string{
|
||||||
|
"url": imageURL,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
|
template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
|
||||||
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", imagePayload)
|
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", string(imagePayload))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package chat_completions
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -170,14 +171,23 @@ func ConvertCliResponseToOpenAI(_ context.Context, _ string, originalRequestRawJ
|
|||||||
mimeType = "image/png"
|
mimeType = "image/png"
|
||||||
}
|
}
|
||||||
imageURL := fmt.Sprintf("data:%s;base64,%s", mimeType, data)
|
imageURL := fmt.Sprintf("data:%s;base64,%s", mimeType, data)
|
||||||
imagePayload := `{"image_url":{"url":""},"type":"image_url"}`
|
|
||||||
imagePayload, _ = sjson.Set(imagePayload, "image_url.url", imageURL)
|
|
||||||
imagesResult := gjson.Get(template, "choices.0.delta.images")
|
imagesResult := gjson.Get(template, "choices.0.delta.images")
|
||||||
if !imagesResult.Exists() || !imagesResult.IsArray() {
|
if !imagesResult.Exists() || !imagesResult.IsArray() {
|
||||||
template, _ = sjson.SetRaw(template, "choices.0.delta.images", `[]`)
|
template, _ = sjson.SetRaw(template, "choices.0.delta.images", `[]`)
|
||||||
}
|
}
|
||||||
|
imageIndex := len(gjson.Get(template, "choices.0.delta.images").Array())
|
||||||
|
imagePayload, err := json.Marshal(map[string]any{
|
||||||
|
"index": imageIndex,
|
||||||
|
"type": "image_url",
|
||||||
|
"image_url": map[string]string{
|
||||||
|
"url": imageURL,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
|
template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
|
||||||
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", imagePayload)
|
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", string(imagePayload))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package chat_completions
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -182,14 +183,23 @@ func ConvertGeminiResponseToOpenAI(_ context.Context, _ string, originalRequestR
|
|||||||
mimeType = "image/png"
|
mimeType = "image/png"
|
||||||
}
|
}
|
||||||
imageURL := fmt.Sprintf("data:%s;base64,%s", mimeType, data)
|
imageURL := fmt.Sprintf("data:%s;base64,%s", mimeType, data)
|
||||||
imagePayload := `{"image_url":{"url":""},"type":"image_url"}`
|
|
||||||
imagePayload, _ = sjson.Set(imagePayload, "image_url.url", imageURL)
|
|
||||||
imagesResult := gjson.Get(template, "choices.0.delta.images")
|
imagesResult := gjson.Get(template, "choices.0.delta.images")
|
||||||
if !imagesResult.Exists() || !imagesResult.IsArray() {
|
if !imagesResult.Exists() || !imagesResult.IsArray() {
|
||||||
template, _ = sjson.SetRaw(template, "choices.0.delta.images", `[]`)
|
template, _ = sjson.SetRaw(template, "choices.0.delta.images", `[]`)
|
||||||
}
|
}
|
||||||
|
imageIndex := len(gjson.Get(template, "choices.0.delta.images").Array())
|
||||||
|
imagePayload, err := json.Marshal(map[string]any{
|
||||||
|
"index": imageIndex,
|
||||||
|
"type": "image_url",
|
||||||
|
"image_url": map[string]string{
|
||||||
|
"url": imageURL,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
|
template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
|
||||||
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", imagePayload)
|
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", string(imagePayload))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,14 +326,23 @@ func ConvertGeminiResponseToOpenAINonStream(_ context.Context, _ string, origina
|
|||||||
mimeType = "image/png"
|
mimeType = "image/png"
|
||||||
}
|
}
|
||||||
imageURL := fmt.Sprintf("data:%s;base64,%s", mimeType, data)
|
imageURL := fmt.Sprintf("data:%s;base64,%s", mimeType, data)
|
||||||
imagePayload := `{"image_url":{"url":""},"type":"image_url"}`
|
|
||||||
imagePayload, _ = sjson.Set(imagePayload, "image_url.url", imageURL)
|
|
||||||
imagesResult := gjson.Get(template, "choices.0.message.images")
|
imagesResult := gjson.Get(template, "choices.0.message.images")
|
||||||
if !imagesResult.Exists() || !imagesResult.IsArray() {
|
if !imagesResult.Exists() || !imagesResult.IsArray() {
|
||||||
template, _ = sjson.SetRaw(template, "choices.0.message.images", `[]`)
|
template, _ = sjson.SetRaw(template, "choices.0.message.images", `[]`)
|
||||||
}
|
}
|
||||||
|
imageIndex := len(gjson.Get(template, "choices.0.message.images").Array())
|
||||||
|
imagePayload, err := json.Marshal(map[string]any{
|
||||||
|
"index": imageIndex,
|
||||||
|
"type": "image_url",
|
||||||
|
"image_url": map[string]string{
|
||||||
|
"url": imageURL,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
template, _ = sjson.Set(template, "choices.0.message.role", "assistant")
|
template, _ = sjson.Set(template, "choices.0.message.role", "assistant")
|
||||||
template, _ = sjson.SetRaw(template, "choices.0.message.images.-1", imagePayload)
|
template, _ = sjson.SetRaw(template, "choices.0.message.images.-1", string(imagePayload))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user