From 0cdec8210fd4cb96ef4d8f23da4a91d064b8580e Mon Sep 17 00:00:00 2001 From: WeiQing Chen <40507679+david6666666@users.noreply.github.com> Date: Tue, 21 Apr 2026 21:37:52 +0800 Subject: [PATCH] [Bugfix] ComfyUI image-to-image DALL-E endpoint cases #2886 (#2980) Signed-off-by: david6666666 <530634352@qq.com> --- tests/comfyui/test_comfyui_integration.py | 1 - .../openai_api/test_image_server.py | 21 +++++++++++++++++++ vllm_omni/entrypoints/openai/api_server.py | 19 +++++++++++++++-- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/tests/comfyui/test_comfyui_integration.py b/tests/comfyui/test_comfyui_integration.py index 5164f3b9a..80e86d824 100644 --- a/tests/comfyui/test_comfyui_integration.py +++ b/tests/comfyui/test_comfyui_integration.py @@ -523,7 +523,6 @@ def api_server(unused_tcp_port_factory, server_case: ServerCase, mock_async_omni "Qwen/Qwen-Image-Edit", True, id="image-to-image-dalle-endpoint", - marks=pytest.mark.skip(reason="Temporarily disabled due to failure."), ), pytest.param( ServerCase( diff --git a/tests/entrypoints/openai_api/test_image_server.py b/tests/entrypoints/openai_api/test_image_server.py index 8a373f74d..4cf46f18c 100644 --- a/tests/entrypoints/openai_api/test_image_server.py +++ b/tests/entrypoints/openai_api/test_image_server.py @@ -1061,6 +1061,27 @@ def test_image_edit_rejects_too_many_images_for_qwen_image_edit_2511_before_load assert engine.captured_prompt is None +def test_image_edit_ignores_mock_like_multimodal_limit(async_omni_test_client): + engine = async_omni_test_client.app.state.engine_client + engine.get_diffusion_od_config = lambda: SimpleNamespace( + supports_multimodal_inputs=SimpleNamespace(), + max_multimodal_image_inputs=SimpleNamespace(), + ) + + response = async_omni_test_client.post( + "/v1/images/edits", + files=[("image", make_test_image_bytes((16, 16)))], + data={"prompt": "hello world."}, + ) + + assert response.status_code == 200 + captured_prompt = engine.captured_prompt + assert captured_prompt is not None + processed_images = captured_prompt["multi_modal_data"]["image"] + assert len(processed_images) == 1 + assert processed_images[0].size == (16, 16) + + def test_image_edit_parameter_pass(async_omni_test_client): img_bytes_1 = make_test_image_bytes((16, 16)) diff --git a/vllm_omni/entrypoints/openai/api_server.py b/vllm_omni/entrypoints/openai/api_server.py index 1def10e64..41ccbcf1d 100644 --- a/vllm_omni/entrypoints/openai/api_server.py +++ b/vllm_omni/entrypoints/openai/api_server.py @@ -16,6 +16,7 @@ from argparse import Namespace from collections.abc import AsyncIterator from contextlib import asynccontextmanager from http import HTTPStatus +from numbers import Integral from typing import Annotated, Any, Literal, cast import httpx @@ -1826,10 +1827,24 @@ def _get_max_edit_input_images(raw_request: Request, engine_client: Any) -> int # config is not exposed on the serving surface. return None - if not bool(getattr(od_config, "supports_multimodal_inputs", False)): + supports_multimodal_inputs = getattr(od_config, "supports_multimodal_inputs", None) + if not isinstance(supports_multimodal_inputs, bool): + # Older serving surfaces and mocked engines may expose a placeholder + # object instead of a real diffusion config. Treat that as "unknown" + # so existing single-image flows keep working. + return None + + if not supports_multimodal_inputs: return 1 - return getattr(od_config, "max_multimodal_image_inputs", None) + max_input_images = getattr(od_config, "max_multimodal_image_inputs", None) + if max_input_images is None: + return None + if isinstance(max_input_images, bool) or not isinstance(max_input_images, Integral): + return None + if max_input_images < 1: + return None + return int(max_input_images) def _get_lora_from_json_str(lora_body):