Skip to content

[Bugfix] Handle numpy array outputs when generate image - #1680

Merged
hsliuustc0106 merged 4 commits into
vllm-project:mainfrom
lengrongfu:fix/image-save
Apr 15, 2026
Merged

hsliuustc0106 merged 4 commits into
vllm-project:mainfrom
lengrongfu:fix/image-save

Conversation

@lengrongfu

@lengrongfu lengrongfu commented Mar 5, 2026 •

Copy link
Copy Markdown
Contributor

PLEASE FILL IN THE PR DESCRIPTION HERE ENSURING ALL CHECKLIST ITEMS (AT THE BOTTOM) HAVE BEEN CONSIDERED.

Purpose

Fixes: #1660

Wan2.2 video pipelines return numpy arrays (output_type="np"), but image_api_utils.py assumes PIL Images and calls img.save().

We _extract_images_from_result this method to add a numpy-to-PIL conversion.

Serve:

vllm serve /home/jovyan/Wan2.2-T2V-A14B-Diffusers/ --omni --port 8091

Test:

curl  -X POST "http://localhost:8091/v1/images/generations"   -H "Content-Type: application/json"   --data '{
            "model": "/home/jovyan/Wan2.2-T2V-A14B-Diffusers/",
            "prompt": "a cat",
            "n": 1,
            "size": "256x256",
            "seed": 7
}' | jq -r '.data[0].b64_json' | base64 -d > cat.png
cat
curl -X POST "http://localhost:8000/v1/images/generations" \
  -H "Content-Type: application/json" \
  --data '{
    "model": "/home/jovyan/Wan2.2-T2V-A14B-Diffusers/",
    "prompt": "a cat",
    "n": 2,
    "size": "256x256",
    "seed": 7
  }' \
| jq -r '.data[].b64_json' \
| nl -v 0 \
| while read i img; do
    echo "$img" | base64 -d > "cat${i}.png"
  done
cat0 cat1

Test Plan

Test Result


Essential Elements of an Effective PR Description Checklist
  • The purpose of the PR, such as "Fix some issue (link existing issues this PR will resolve)".
  • The test plan. Please provide the test scripts & test commands. Please state the reasons if your codes don't require additional test scripts. For test file guidelines, please check the test style doc
  • The test results. Please paste the results comparison before and after, or the e2e results.
  • (Optional) The necessary documentation update, such as updating supported_models.md and examples for a new model. Please run mkdocs serve to sync the documentation editions to ./docs.
  • (Optional) Release notes update. If your change is user-facing, please update the release notes draft.

BEFORE SUBMITTING, PLEASE READ https://github.com/vllm-project/vllm-omni/blob/main/CONTRIBUTING.md (anything written below this line will be removed by GitHub Actions)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 08bb4cf9b7

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread vllm_omni/entrypoints/openai/api_server.py Outdated
@hsliuustc0106

Copy link
Copy Markdown
Collaborator

why use /v1/images/generations as the endpoint?

@lengrongfu

Copy link
Copy Markdown
Contributor Author

Sorry, I checked the example and it shows that this API is used. Is it not usable?

@hsliuustc0106 hsliuustc0106 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Review

Rating: 6/10 | Verdict: ⚠️ Changes Requested

Summary

Bugfix addresses valid issue (Wan2.2 returning numpy arrays), but implementation has critical edge cases and missing tests. Code logic is unclear and needs refactoring.

Issues

  1. Critical: IndexError on empty list - Line 1424 checks images[0] without verifying the list is non-empty. Will crash if images is empty.

  2. Confusing logic - Line 1425 images = images[0] is unclear. Is this handling a nested array case? Needs comment explaining the expected structure.

  3. Missing tests - No unit tests for the new _normalize_image function or the modified _extract_images_from_result.

  4. Incomplete PR description - Checklist items not filled, no test results provided.

  5. Edge cases not handled:

    • Empty images list
    • Mixed types (some PIL, some numpy)
    • Unsupported dtype (e.g., bool, complex)

Highlights

  • ✅ Addresses real issue (Wan2.2 compatibility)
  • ✅ Handles multiple normalization cases (float [0,1] and [-1,1])
  • ✅ Properly handles ndim > 3 case

Recommendation

Fix edge cases and add tests before merge.


Reviewed by OpenClaw with vllm-omni-skills 🦐

elif hasattr(request_output, "images") and request_output.images:
images = request_output.images
return images
if isinstance(images[0], np.ndarray):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This will raise IndexError if images is empty. Add a guard: if images and isinstance(images[0], np.ndarray):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

thanks tips ~

images = request_output.images
return images
if isinstance(images[0], np.ndarray):
images = images[0]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This logic is confusing. If images[0] is a numpy array, you replace the entire images list with images[0]. Is this handling a nested array structure like [np_array_of_frames]? Add a comment explaining the expected input format.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes, when generate more one image this array structure is np_array_of_frames. like:

images = np.array([
    [[...], [...], ...],  # one png (256, 256, 3)
    [[...], [...], ...],  # two png (256, 256, 3)
    [[...], [...], ...],  # three png (256, 256, 3)
])
# shape: (3, 256, 256, 3)

setattr(object, key, val)


def _normalize_image(image: Any) -> Any:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The function handles floating dtypes but doesn't check for unsupported types (e.g., bool, complex). Consider adding: if not np.issubdtype(image.dtype, np.integer) and not np.issubdtype(image.dtype, np.floating): raise ValueError(f"Unsupported dtype: {image.dtype}")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

thanks tips ~

def _normalize_image(image: Any) -> Any:
"""Normalize a single image output to a PIL-compatible format."""
if isinstance(image, np.ndarray):
while image.ndim > 3:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The normalization assumes float range is either [-1, 1] or [0, 1]. What about other ranges? Consider adding a debug log or warning when rescaling from [-1, 1] range to help diagnose issues.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

add warning log.

if isinstance(images[0], np.ndarray):
images = images[0]
return [_normalize_image(img) for img in images]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Missing unit test for _normalize_image and _extract_images_from_result. At minimum, add tests for: (1) numpy array with float [0,1], (2) numpy array with float [-1,1], (3) numpy array with int, (4) already PIL Image, (5) empty list.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

add unit test

@gcanlin

gcanlin commented Mar 9, 2026

Copy link
Copy Markdown
Collaborator

@lishunyang12 PTAL. Thanks!

@lishunyang12

Copy link
Copy Markdown
Collaborator

Will take a look.

@lishunyang12 lishunyang12 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The idea is right but there are two bugs in the implementation.

Comment thread vllm_omni/entrypoints/openai/api_server.py
Comment thread vllm_omni/entrypoints/openai/api_server.py Outdated
@hsliuustc0106
hsliuustc0106 self-requested a review March 22, 2026 01:47
@hsliuustc0106 hsliuustc0106 added the ready label to trigger buildkite CI label Mar 22, 2026
Signed-off-by: rongfu.leng <lenronfu@gmail.com>
Signed-off-by: rongfu.leng <lenronfu@gmail.com>
Signed-off-by: rongfu.leng <lenronfu@gmail.com>
Signed-off-by: rongfu.leng <lenronfu@gmail.com>

@gcanlin gcanlin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could you upload the generated images?

@lengrongfu

Copy link
Copy Markdown
Contributor Author

Could you upload the generated images?

Uploaded, currently, generating multiple photos via HTTP is quite inconvenient, as the response consists of JSON data. I would appreciate it if you could take a look at this PR #1673, which proposes returning the images directly as files. @gcanlin

@Gaohan123 Gaohan123 modified the milestones: v0.18.0, v0.20.0 Apr 14, 2026
@hsliuustc0106
hsliuustc0106 merged commit 9e46a79 into vllm-project:main Apr 15, 2026
8 checks passed
y123456y78 pushed a commit to y123456y78/vllm-omni that referenced this pull request Apr 15, 2026
lvliang-intel pushed a commit to lvliang-intel/vllm-omni that referenced this pull request Apr 20, 2026
lengrongfu added a commit to lengrongfu/vllm-omni that referenced this pull request May 1, 2026
clodaghwalsh17 pushed a commit to clodaghwalsh17/nm-vllm-omni-ent that referenced this pull request May 12, 2026
daixinning pushed a commit to daixinning/vllm-omni that referenced this pull request May 28, 2026
quyifei23 pushed a commit to quyifei23/vllm-omni that referenced this pull request Jun 6, 2026
khairulkabir1661 pushed a commit to khairulkabir1661/vllm-omni that referenced this pull request Sep 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready label to trigger buildkite CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants