-
-
Notifications
You must be signed in to change notification settings - Fork 94
fix(openai): add index field to image response for LiteLLM compatibility #63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ package chat_completions | |
| import ( | ||
| "bytes" | ||
| "context" | ||
| "encoding/json" | ||
| "fmt" | ||
| "strings" | ||
| "sync/atomic" | ||
|
|
@@ -170,14 +171,23 @@ func ConvertCliResponseToOpenAI(_ context.Context, _ string, originalRequestRawJ | |
| mimeType = "image/png" | ||
| } | ||
| 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") | ||
| if !imagesResult.Exists() || !imagesResult.IsArray() { | ||
| 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.SetRaw(template, "choices.0.delta.images.-1", imagePayload) | ||
| template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", string(imagePayload)) | ||
|
Comment on lines
+178
to
+190
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This block of code for creating and appending an image payload is duplicated in other response translator files ( Additionally, for better type safety and readability, it's recommended to use a struct for JSON marshaling instead of a imageIndex := len(gjson.Get(template, "choices.0.delta.images").Array())
type imagePayload struct {
Index int `json:"index"`
Type string `json:"type"`
ImageURL map[string]string `json:"image_url"`
}
payload := imagePayload{
Index: imageIndex,
Type: "image_url",
ImageURL: map[string]string{
"url": imageURL,
},
}
imagePayloadBytes, err := json.Marshal(payload)
if err != nil {
continue
}
template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", string(imagePayloadBytes)) |
||
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ package chat_completions | |
| import ( | ||
| "bytes" | ||
| "context" | ||
| "encoding/json" | ||
| "fmt" | ||
| "strings" | ||
| "sync/atomic" | ||
|
|
@@ -182,14 +183,23 @@ func ConvertGeminiResponseToOpenAI(_ context.Context, _ string, originalRequestR | |
| mimeType = "image/png" | ||
| } | ||
| 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") | ||
| if !imagesResult.Exists() || !imagesResult.IsArray() { | ||
| 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.SetRaw(template, "choices.0.delta.images.-1", imagePayload) | ||
| template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", string(imagePayload)) | ||
|
Comment on lines
+190
to
+202
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This block of code for creating and appending an image payload is duplicated elsewhere in this file and in other response translator files. To improve maintainability and reduce redundancy, consider extracting this logic into a single, reusable helper function. For better type safety and readability, it's also recommended to use a struct for JSON marshaling instead of a Finally, it would be beneficial to log the error from imageIndex := len(gjson.Get(template, "choices.0.delta.images").Array())
type imagePayload struct {
Index int `json:"index"`
Type string `json:"type"`
ImageURL map[string]string `json:"image_url"`
}
payload := imagePayload{
Index: imageIndex,
Type: "image_url",
ImageURL: map[string]string{
"url": imageURL,
},
}
imagePayloadBytes, err := json.Marshal(payload)
if err != nil {
log.Warnf("gemini openai response: failed to marshal image payload in streaming: %v", err)
continue
}
template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", string(imagePayloadBytes)) |
||
| } | ||
| } | ||
| } | ||
|
|
@@ -316,14 +326,23 @@ func ConvertGeminiResponseToOpenAINonStream(_ context.Context, _ string, origina | |
| mimeType = "image/png" | ||
| } | ||
| 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") | ||
| if !imagesResult.Exists() || !imagesResult.IsArray() { | ||
| 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.SetRaw(template, "choices.0.message.images.-1", imagePayload) | ||
| template, _ = sjson.SetRaw(template, "choices.0.message.images.-1", string(imagePayload)) | ||
|
Comment on lines
+333
to
+345
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This block of code for creating and appending an image payload is duplicated elsewhere in this file and in other response translator files. To improve maintainability and reduce redundancy, consider extracting this logic into a single, reusable helper function. For better type safety and readability, it's also recommended to use a struct for JSON marshaling instead of a Finally, it would be beneficial to log the error from imageIndex := len(gjson.Get(template, "choices.0.message.images").Array())
type imagePayload struct {
Index int `json:"index"`
Type string `json:"type"`
ImageURL map[string]string `json:"image_url"`
}
payload := imagePayload{
Index: imageIndex,
Type: "image_url",
ImageURL: map[string]string{
"url": imageURL,
},
}
imagePayloadBytes, err := json.Marshal(payload)
if err != nil {
log.Warnf("gemini openai response: failed to marshal image payload in non-streaming: %v", err)
continue
}
template, _ = sjson.Set(template, "choices.0.message.role", "assistant")
template, _ = sjson.SetRaw(template, "choices.0.message.images.-1", string(imagePayloadBytes)) |
||
| } | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This block of code for creating and appending an image payload is duplicated in other response translator files (
gemini-cli_openai_response.go,gemini_openai_response.go). To improve maintainability and reduce redundancy, consider extracting this logic into a single, reusable helper function in a shared package.For better type safety and readability, it's also recommended to use a struct for JSON marshaling instead of a
map[string]any.Finally, it would be beneficial to log the error from
json.Marshalto aid in debugging, as it's currently being silently ignored.