Skip to content

fix(provider): 修复 base64:// 图片引用的 MIME 类型声明不准确问题#8177

Open
NayukiChiba wants to merge 1 commit into
AstrBotDevs:masterfrom
NayukiChiba:fix/8174-img-format
Open

fix(provider): 修复 base64:// 图片引用的 MIME 类型声明不准确问题#8177
NayukiChiba wants to merge 1 commit into
AstrBotDevs:masterfrom
NayukiChiba:fix/8174-img-format

Conversation

@NayukiChiba
Copy link
Copy Markdown
Contributor

@NayukiChiba NayukiChiba commented May 13, 2026

  • 新增 _detect_image_format 方法,使用 Pillow verify() 检测图片真实格式,避免完整解码像素带来的额外开销
  • 新增 _base64_image_ref_to_data_url 方法,将 base64:// 引用转换为携带真实 MIME 类型的 data URL,修复 PNG/GIF/WebP 等图片被错误声明为 image/jpeg 的问题
  • 提取 _IMAGE_FORMAT_MIME_TYPES 类常量和 _image_format_to_mime_type 方法,统一本地文件与 base64:// 引用的格式映射逻辑,新增 TIFF/AVIF 格式支持
  • 新增单元测试 test_resolve_image_part_preserves_base64_png_mime_type,覆盖 PNG 图片 MIME 类型正确声明的场景

Closes #8174

Modifications / 改动点

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

(astrbot) PS > uv run pytest tests/test_openai_source.py::test_resolve_image_part_preserves_base64_png_mime_type
================================== test session starts ==================================
platform win32 -- Python 3.12.12, pytest-9.0.2, pluggy-1.6.0
rootdir: D:\Nayey\Code\NayukiChiba\AstrBot
configfile: pyproject.toml
plugins: anyio-4.12.1, asyncio-1.3.0, cov-7.0.0
asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collected 1 item
tests\test_openai_source.py .
1 passed in 1.64s

Checklist / 检查清单

  • 😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
    / 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。

  • 👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
    / 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”

  • 🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
    / 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到 requirements.txtpyproject.toml 文件相应位置。

  • 😮 My changes do not introduce malicious code.
    / 我的更改没有引入恶意代码。

Summary by Sourcery

Ensure base64:// image references are converted to data URLs with correctly detected MIME types and extend image format support.

Bug Fixes:

  • Preserve the true MIME type when converting base64:// image references to data URLs instead of defaulting to image/jpeg.

Enhancements:

  • Centralize image format-to-MIME-type mapping, including support for TIFF and AVIF formats, and reuse it for both file-based and base64 image inputs.

Tests:

  • Add an async test to verify that PNG images passed via base64:// retain image/png in the resulting data URL.

- 新增 `_detect_image_format` 方法,使用 Pillow verify() 检测图片真实格式,避免完整解码像素带来的额外开销
- 新增 `_base64_image_ref_to_data_url` 方法,将 base64:// 引用转换为携带真实 MIME 类型的 data URL,修复 PNG/GIF/WebP 等图片被错误声明为 image/jpeg 的问题
- 提取 `_IMAGE_FORMAT_MIME_TYPES` 类常量和 `_image_format_to_mime_type` 方法,统一本地文件与 base64:// 引用的格式映射逻辑,新增 TIFF/AVIF 格式支持
- 新增单元测试 `test_resolve_image_part_preserves_base64_png_mime_type`,覆盖 PNG 图片 MIME 类型正确声明的场景

Closes AstrBotDevs#8174
@auto-assign auto-assign Bot requested review from Fridemn and Soulter May 13, 2026 14:45
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. labels May 13, 2026
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • In _base64_image_ref_to_data_url, you catch binascii.Error from base64.b64decode but binascii is not defined in this file; consider either importing binascii explicitly or catching the exception via base64.binascii.Error (or a broader Exception) to avoid a NameError at runtime.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `_base64_image_ref_to_data_url`, you catch `binascii.Error` from `base64.b64decode` but `binascii` is not defined in this file; consider either importing `binascii` explicitly or catching the exception via `base64.binascii.Error` (or a broader `Exception`) to avoid a `NameError` at runtime.

## Individual Comments

### Comment 1
<location path="tests/test_openai_source.py" line_range="1045-1047" />
<code_context>
+            image_buffer,
+            format="PNG",
+        )
+        image_base64 = base64.b64encode(image_buffer.getvalue()).decode("ascii")
+
+        image_part = await provider._resolve_image_part(f"base64://{image_base64}")
+
+        assert image_part == {
</code_context>
<issue_to_address>
**suggestion (testing):** Add a test for invalid or malformed base64 inputs to ensure legacy JPEG behavior is preserved

Since `_base64_image_ref_to_data_url` is intended to preserve the existing behavior for invalid/malformed base64 (or non-image) input by still returning a JPEG data URL, please add a test where `image_ref` is `base64://` plus an invalid base64 string (e.g. `"not-base64"`) and assert that `_resolve_image_part` still returns a `data:image/jpeg;base64,...` URL rather than raising. This will explicitly cover the backward-compatibility case described in the implementation comments.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +1045 to +1047
image_base64 = base64.b64encode(image_buffer.getvalue()).decode("ascii")

image_part = await provider._resolve_image_part(f"base64://{image_base64}")
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.

suggestion (testing): Add a test for invalid or malformed base64 inputs to ensure legacy JPEG behavior is preserved

Since _base64_image_ref_to_data_url is intended to preserve the existing behavior for invalid/malformed base64 (or non-image) input by still returning a JPEG data URL, please add a test where image_ref is base64:// plus an invalid base64 string (e.g. "not-base64") and assert that _resolve_image_part still returns a data:image/jpeg;base64,... URL rather than raising. This will explicitly cover the backward-compatibility case described in the implementation comments.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request implements dynamic MIME type detection for image attachments within the OpenAI provider, replacing the previous hardcoded JPEG default for base64:// references. It introduces helper methods for format detection and MIME mapping, along with corresponding unit tests. Feedback suggested a minor performance optimization for large base64 strings during format detection.

# 平台适配器可能通过 `base64://` 传入 PNG/GIF/WebP 等图片字节,
# 但不会额外携带 MIME 元数据。发送 OpenAI 请求前先识别真实格式,
# 避免把 PNG 等图片错误声明为 JPEG。
image_bytes = base64.b64decode(raw_base64)
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.

medium

Decoding the entire base64 string into memory just to detect the image format can be inefficient for very large images. Since most image headers are within the first few dozen bytes, you could potentially optimize this by decoding only the beginning of the string. However, given that the full base64 is required for the final data URL and Pillow's verify() is relatively lightweight, this is a minor performance consideration. Additionally, as this introduces new functionality for handling attachments, please ensure it is accompanied by corresponding unit tests.

References
  1. New functionality, such as handling attachments, should be accompanied by corresponding unit tests.

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

Labels

area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]向 LLM 发送图片时似乎会触发 500 报错,疑似图片 JSON 格式兼容问题

1 participant