From 00b850a44f6f42da1327237f4e13695b72df4193 Mon Sep 17 00:00:00 2001 From: VectorPeak <73048950+VectorPeak@users.noreply.github.com> Date: Sat, 18 Jul 2026 20:18:51 +0800 Subject: [PATCH 1/2] fix: return correct WebChat image MIME types Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com> --- astrbot/dashboard/services/chat_service.py | 12 ++++-- .../unit/test_webchat_upload_image_format.py | 38 +++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/astrbot/dashboard/services/chat_service.py b/astrbot/dashboard/services/chat_service.py index 36b0700b92..fd74846303 100644 --- a/astrbot/dashboard/services/chat_service.py +++ b/astrbot/dashboard/services/chat_service.py @@ -504,7 +504,13 @@ def __init__( self.webchat_img_dir = os.path.join(get_astrbot_data_path(), "webchat", "imgs") os.makedirs(self.attachments_dir, exist_ok=True) - self.supported_imgs = ["jpg", "jpeg", "png", "gif", "webp"] + self.supported_img_mime_types = { + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".png": "image/png", + ".gif": "image/gif", + ".webp": "image/webp", + } self.conv_mgr = core_lifecycle.conversation_manager self.platform_history_mgr = core_lifecycle.platform_message_history_manager self.umop_config_router = core_lifecycle.umop_config_router @@ -557,8 +563,8 @@ async def resolve_webchat_file( filename_ext = file_path.suffix.lower() if filename_ext == ".wav": return str(file_path), "audio/wav" - if filename_ext[1:] in self.supported_imgs: - return str(file_path), "image/jpeg" + if filename_ext in self.supported_img_mime_types: + return str(file_path), self.supported_img_mime_types[filename_ext] return str(file_path), None async def resolve_webchat_file_from_dashboard_query( diff --git a/tests/unit/test_webchat_upload_image_format.py b/tests/unit/test_webchat_upload_image_format.py index 14cce65501..06c43839e7 100644 --- a/tests/unit/test_webchat_upload_image_format.py +++ b/tests/unit/test_webchat_upload_image_format.py @@ -44,3 +44,41 @@ async def insert_attachment(self, path, type, mime_type): assert fake_db.inserted["type"] == "image" assert (tmp_path / result["filename"]).exists() assert not (tmp_path / "pasted.png").exists() + + +@pytest.mark.parametrize( + ("filename", "expected_mime_type"), + [ + ("photo.jpg", "image/jpeg"), + ("photo.jpeg", "image/jpeg"), + ("photo.png", "image/png"), + ("photo.gif", "image/gif"), + ("photo.webp", "image/webp"), + ], +) +@pytest.mark.asyncio +async def test_resolve_webchat_file_uses_image_extension_mime_type( + tmp_path, + monkeypatch, + filename, + expected_mime_type, +): + monkeypatch.setattr( + "astrbot.dashboard.services.chat_service.get_astrbot_data_path", + lambda: str(tmp_path), + ) + service = ChatService( + SimpleNamespace(), + SimpleNamespace( + conversation_manager=None, + platform_message_history_manager=None, + umop_config_router=None, + ), + ) + file_path = tmp_path / "attachments" / filename + file_path.write_bytes(b"image-bytes") + + resolved_path, mime_type = await service.resolve_webchat_file(filename) + + assert resolved_path == str(file_path.resolve(strict=False)) + assert mime_type == expected_mime_type From a54203acbf2587c8ed883f0496618b7a3e558873 Mon Sep 17 00:00:00 2001 From: VectorPeak <73048950+VectorPeak@users.noreply.github.com> Date: Sat, 18 Jul 2026 20:39:28 +0800 Subject: [PATCH 2/2] fix: centralize WebChat image MIME mapping Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com> --- astrbot/dashboard/services/chat_service.py | 18 +++++++++--------- tests/unit/test_webchat_upload_image_format.py | 13 +++++-------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/astrbot/dashboard/services/chat_service.py b/astrbot/dashboard/services/chat_service.py index fd74846303..a1bd86883d 100644 --- a/astrbot/dashboard/services/chat_service.py +++ b/astrbot/dashboard/services/chat_service.py @@ -36,6 +36,13 @@ SSE_HEARTBEAT = ": heartbeat\n\n" CHAT_RUN_SUBSCRIBER_QUEUE_SIZE = 256 +WEBCHAT_IMAGE_MIME_TYPES = { + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".png": "image/png", + ".gif": "image/gif", + ".webp": "image/webp", +} def sanitize_upload_filename(filename: str | None) -> str: @@ -504,13 +511,6 @@ def __init__( self.webchat_img_dir = os.path.join(get_astrbot_data_path(), "webchat", "imgs") os.makedirs(self.attachments_dir, exist_ok=True) - self.supported_img_mime_types = { - ".jpg": "image/jpeg", - ".jpeg": "image/jpeg", - ".png": "image/png", - ".gif": "image/gif", - ".webp": "image/webp", - } self.conv_mgr = core_lifecycle.conversation_manager self.platform_history_mgr = core_lifecycle.platform_message_history_manager self.umop_config_router = core_lifecycle.umop_config_router @@ -563,8 +563,8 @@ async def resolve_webchat_file( filename_ext = file_path.suffix.lower() if filename_ext == ".wav": return str(file_path), "audio/wav" - if filename_ext in self.supported_img_mime_types: - return str(file_path), self.supported_img_mime_types[filename_ext] + if filename_ext in WEBCHAT_IMAGE_MIME_TYPES: + return str(file_path), WEBCHAT_IMAGE_MIME_TYPES[filename_ext] return str(file_path), None async def resolve_webchat_file_from_dashboard_query( diff --git a/tests/unit/test_webchat_upload_image_format.py b/tests/unit/test_webchat_upload_image_format.py index 06c43839e7..7125c6961f 100644 --- a/tests/unit/test_webchat_upload_image_format.py +++ b/tests/unit/test_webchat_upload_image_format.py @@ -4,7 +4,10 @@ import pytest from PIL import Image as PILImage -from astrbot.dashboard.services.chat_service import ChatService +from astrbot.dashboard.services.chat_service import ( + WEBCHAT_IMAGE_MIME_TYPES, + ChatService, +) @pytest.mark.asyncio @@ -48,13 +51,7 @@ async def insert_attachment(self, path, type, mime_type): @pytest.mark.parametrize( ("filename", "expected_mime_type"), - [ - ("photo.jpg", "image/jpeg"), - ("photo.jpeg", "image/jpeg"), - ("photo.png", "image/png"), - ("photo.gif", "image/gif"), - ("photo.webp", "image/webp"), - ], + [(f"photo{ext}", mime_type) for ext, mime_type in WEBCHAT_IMAGE_MIME_TYPES.items()], ) @pytest.mark.asyncio async def test_resolve_webchat_file_uses_image_extension_mime_type(