Skip to content

[codex] Support Gemini image inputs in generations - #5742

Closed
neta-zjj wants to merge 1 commit into
QuantumNous:mainfrom
neta-zjj:feat_generation_image_input_url
Closed

[codex] Support Gemini image inputs in generations#5742
neta-zjj wants to merge 1 commit into
QuantumNous:mainfrom
neta-zjj:feat_generation_image_input_url

Conversation

@neta-zjj

@neta-zjj neta-zjj commented Jun 25, 2026

Copy link
Copy Markdown

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

为 Gemini image generation models 的 /v1/images/generations 兼容入口增加输入图支持。现在 image / images 可以接收 URL、data URI、裸 base64,以及 OpenAI 风格的 { "image_url": { "url": "..." } }{ "b64_json": "..." } 对象。

实现上把 image / images 统一解析成 FileSource,复用已有文件下载和 base64 解码逻辑,再转换为 Gemini generateContentinlineData parts。Imagen 模型仍保留原来的 prompt-only :predict 请求;如果请求带输入图但路由到 Imagen,会明确报错,避免静默忽略输入图。

Gemini generateContent 返回的 inline image 会转换回 OpenAI Images API 的 data[].b64_json 响应形状。Vertex Gemini 路径复用同一个响应转换。

本 PR 由 AI-assisted 方式实现,提交者不是该仓库历史核心维护者。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes # (如有)

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

GOTOOLCHAIN=local GOPROXY=https://goproxy.cn,direct /usr/local/go1.26/bin/go test ./dto ./relay/channel/gemini ./relay/channel/vertex ./setting/model_setting

结果:

ok   github.com/QuantumNous/new-api/dto
ok   github.com/QuantumNous/new-api/relay/channel/gemini
?    github.com/QuantumNous/new-api/relay/channel/vertex [no test files]
ok   github.com/QuantumNous/new-api/setting/model_setting

Summary by CodeRabbit

  • New Features

    • Added support for image inputs in more formats, including URLs, inline data, and nested image objects.
    • Enabled Gemini image generation routing so image requests can be converted and returned as generated images.
    • Expanded supported Gemini image-generation models.
  • Bug Fixes

    • Improved validation for invalid image inputs and unsupported image content.
    • Added clearer handling for empty image results and upstream error conditions.
    • Improved token usage reporting for generated images.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds OpenAI image-input parsing, converts supported image-generation requests into Gemini generateContent payloads, and adds Gemini/Vertex response handling for generated images. Tests cover parsing, conversion, and response handling.

Changes

Gemini image generation relay

Layer / File(s) Summary
OpenAI image source parsing
dto/openai_image.go, dto/openai_image_test.go
ImageRequest.InputImageSources() parses image and images JSON values into []types.FileSource, and tests cover supported shapes plus scalar rejection.
Gemini request conversion
relay/channel/gemini/adaptor.go, setting/model_setting/gemini.go, relay/channel/gemini/image_generation_test.go
ConvertImageRequest routes supported image requests into Gemini generateContent payloads with inline image parts, response modalities, and image config mapping; the supported imagine model list adds nano-banana-pro-preview, and tests cover the converted request shape.
Gemini image response handling
relay/channel/gemini/relay-gemini.go, relay/channel/vertex/adaptor.go, relay/channel/gemini/image_generation_test.go
GeminiGenerateContentImageHandler turns Gemini inline image candidates into OpenAI image responses, GeminiImageHandler switches serialization to common.Marshal, and Gemini/Vertex response routing dispatches ImagesGenerations to the new handler; tests cover handler output and usage totals.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant GeminiAdaptor
  participant Base64Loader as service.GetBase64Data
  participant GeminiGenerateContentImageHandler
  participant VertexAdaptor
  Client->>GeminiAdaptor: ConvertImageRequest(ImageRequest)
  GeminiAdaptor->>Base64Loader: GetBase64Data(source)
  VertexAdaptor->>GeminiGenerateContentImageHandler: handle RelayModeImagesGenerations
  GeminiGenerateContentImageHandler->>Client: write dto.ImageResponse JSON
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • creamlike1024

Poem

A bunny hopped through image streams so bright,
Then Gemini nibbled bytes just right.
It plucked a pic from JSON leaves,
And bounced it back in b64 eaves 🐇
Hoppy relays sing through the night.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding Gemini image input support for generation requests.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
dto/openai_image_test.go (1)

27-50: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use assert for the value checks in these new tests.

These expectations are non-fatal checks, so keeping them as require stops the test at the first mismatch and misses later diagnostics. As per coding guidelines, “New or substantially rewritten Go backend tests MUST use github.com/stretchr/testify/require for setup and fatal assertions, and github.com/stretchr/testify/assert for non-fatal value checks.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dto/openai_image_test.go` around lines 27 - 50, The new tests in
ImageRequest.InputImageSources are using require for non-fatal value checks,
which should be converted to assert while keeping require only for setup and
fatal failures. Update the type/value expectations in
TestImageRequestInputImageSources to use assert for checks like Len, True, and
Equal, and leave the error-path setup in
TestImageRequestInputImageSourcesRejectsScalarJSON as require-based where
appropriate.

Source: Coding guidelines

relay/channel/gemini/image_generation_test.go (1)

40-53: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use assert for the non-fatal expectations in these new tests.

Most checks here are value assertions after setup has already succeeded, so assert is the better fit and matches the repository test convention. As per coding guidelines, “New or substantially rewritten Go backend tests MUST use github.com/stretchr/testify/require for setup and fatal assertions, and github.com/stretchr/testify/assert for non-fatal value checks.”

Also applies to: 77-81

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@relay/channel/gemini/image_generation_test.go` around lines 40 - 53, The new
Gemini image generation test is using require for non-fatal value checks after
setup has already succeeded; update image_generation_test.go in the test body
around the GeminiChatRequest assertions to use assert for value comparisons
while keeping require only for setup/fatal conditions. Keep the existing require
checks for type assertion, lengths, and unmarshaling if they guard test setup,
and switch the remaining equality/non-nil checks on GeminiChatRequest,
GenerationConfig.ResponseModalities, and imageConfig to assert to match the
repository convention.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@dto/openai_image.go`:
- Around line 251-279: parseImageSourceObject currently skips recognized image
fields when they have the wrong JSON type, which can silently downgrade
malformed image-edit payloads into prompt-only requests. Update
parseImageSourceObject to validate each recognized key such as image_url, url,
b64_json, base64, and data and return an error when a present field is not the
expected string/object shape instead of continuing; keep the recursive handling
for nested image_url objects, but make malformed recognized fields fail fast
with a 4xx-style validation error.

---

Nitpick comments:
In `@dto/openai_image_test.go`:
- Around line 27-50: The new tests in ImageRequest.InputImageSources are using
require for non-fatal value checks, which should be converted to assert while
keeping require only for setup and fatal failures. Update the type/value
expectations in TestImageRequestInputImageSources to use assert for checks like
Len, True, and Equal, and leave the error-path setup in
TestImageRequestInputImageSourcesRejectsScalarJSON as require-based where
appropriate.

In `@relay/channel/gemini/image_generation_test.go`:
- Around line 40-53: The new Gemini image generation test is using require for
non-fatal value checks after setup has already succeeded; update
image_generation_test.go in the test body around the GeminiChatRequest
assertions to use assert for value comparisons while keeping require only for
setup/fatal conditions. Keep the existing require checks for type assertion,
lengths, and unmarshaling if they guard test setup, and switch the remaining
equality/non-nil checks on GeminiChatRequest,
GenerationConfig.ResponseModalities, and imageConfig to assert to match the
repository convention.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0794084f-16dd-42f1-979e-af93b8214074

📥 Commits

Reviewing files that changed from the base of the PR and between 9ba251c and bd8e436.

📒 Files selected for processing (7)
  • dto/openai_image.go
  • dto/openai_image_test.go
  • relay/channel/gemini/adaptor.go
  • relay/channel/gemini/image_generation_test.go
  • relay/channel/gemini/relay-gemini.go
  • relay/channel/vertex/adaptor.go
  • setting/model_setting/gemini.go

Comment thread dto/openai_image.go
Comment on lines +251 to +279
func parseImageSourceObject(raw json.RawMessage) (string, error) {
var item map[string]json.RawMessage
if err := common.Unmarshal(raw, &item); err != nil {
return "", err
}

for _, key := range []string{"url", "image_url", "b64_json", "base64", "data"} {
rawValue, ok := item[key]
if !ok || common.GetJsonType(rawValue) == "null" {
continue
}
if key == "image_url" && common.GetJsonType(rawValue) == "object" {
if value, err := parseImageSourceObject(rawValue); err != nil || value != "" {
return value, err
}
continue
}
if common.GetJsonType(rawValue) != "string" {
continue
}
var value string
if err := common.Unmarshal(rawValue, &value); err != nil {
return "", err
}
if strings.TrimSpace(value) != "" {
return value, nil
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject malformed recognized image-object fields instead of silently dropping them.

parseImageSourceObject() currently skips recognized keys when their value type is wrong, so inputs like {"image_url":{"url":123}} or {"b64_json":123} can be treated as “no image provided”. With a non-empty prompt, that turns an image-edit request into prompt-only generation instead of returning a 4xx validation error.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dto/openai_image.go` around lines 251 - 279, parseImageSourceObject currently
skips recognized image fields when they have the wrong JSON type, which can
silently downgrade malformed image-edit payloads into prompt-only requests.
Update parseImageSourceObject to validate each recognized key such as image_url,
url, b64_json, base64, and data and return an error when a present field is not
the expected string/object shape instead of continuing; keep the recursive
handling for nested image_url objects, but make malformed recognized fields fail
fast with a 4xx-style validation error.

@neta-zjj

Copy link
Copy Markdown
Author

Closing this draft because the scope is wrong. We should not change the official streaming API; the Generation path needs to be reworked separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant