[PR #20238] [CLOSED] fix: image editing with uploaded images after file storage refactor #48562

Closed
opened 2026-04-30 00:34:51 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/open-webui/open-webui/pull/20238
Author: @Classic298
Created: 12/29/2025
Status: Closed

Base: devHead: image-edits


📝 Commits (10+)

  • 2ec1215 Add standalone prune script with full prune.py functionality
  • 9455912 Complete modular prune system with interactive UI and comprehensive testing
  • d5442a6 Add validation test script for prune system
  • a5b7091 Add Milvus and Milvus Multitenancy vector database cleaners
  • 64d0b60 Update documentation to reflect Milvus vector database support
  • aa95fa7 Add 100% vector database coverage for Milvus multitenancy cleanup
  • 61bd9a3 Fix Milvus API usage: use utility.drop_collection and add collection.flush()
  • cf356ff Add pagination for Milvus multitenancy to handle >16k resources
  • 348c128 Fix CRITICAL pagination bug: replace offset with query_iterator for Milvus multitenancy
  • fe6783c Merge pull request #19030 from open-webui/dev

📊 Changes

17 files changed (+6516 additions, -3 deletions)

View changed files

📝 backend/open_webui/models/channels.py (+129 -0)
📝 backend/open_webui/routers/audio.py (+1 -1)
📝 backend/open_webui/routers/files.py (+1 -1)
📝 backend/open_webui/routers/images.py (+21 -0)
📝 backend/open_webui/utils/middleware.py (+5 -1)
prune/README.md (+502 -0)
prune/prune.py (+177 -0)
prune/prune_cli_interactive.py (+825 -0)
prune/prune_core.py (+1805 -0)
prune/prune_imports.py (+185 -0)
prune/prune_models.py (+116 -0)
prune/prune_operations.py (+644 -0)
prune/requirements.txt (+24 -0)
prune/run_prune.sh (+95 -0)
prune/standalone_prune.py (+826 -0)
prune/test_prune.py (+899 -0)
prune/validate_structure.py (+261 -0)

📄 Description

Description

This PR fixes image editing functionality that broke after the v0.42/v0.43 refactoring which changed how images are stored in chats. Previously, images were stored as base64 data directly in the chat JSON. After the refactor, images are stored as Files in the database and referenced in the chat JSON as URLs (file IDs) for page loading speedup and caching benefits.

This change inadvertently broke image editing because the backend code was not updated to handle the new image storage format.

Root Cause Analysis

Bug 1: get_images_from_messages only checked type == "image"

Location: backend/open_webui/utils/middleware.py

The get_images_from_messages function extracts images from chat messages to determine whether to trigger image editing vs image generation. It only checked for file.get("type") == "image".

However, when images are uploaded through the file upload API (non-temporary chats), they are stored with:

  • type: 'file' (not 'image')
  • content_type: 'image/png' (or other image MIME type)
  • url: '{file_id}'

This caused uploaded images to be completely ignored, resulting in the image generation path being taken instead of image editing.

Note: The frontend already correctly handles both cases in Chat.svelte:

const imageFiles = (message?.files ?? []).filter(
    (file) => file.type === 'image' || (file?.content_type ?? '').startsWith('image/')
);

Bug 2: load_url_image didn't handle raw file IDs

Location: backend/open_webui/routers/images.py

The load_url_image function in the image_edits endpoint converts image URLs to base64 data before sending to the image editing API. It handled:

  • URLs starting with http:// or https://
  • URLs starting with /api/v1/files
  • Base64 data URLs (returned as-is)

However, when an image is uploaded via the file upload API, the frontend sets file.url to just the file ID (e.g., abc123-def456-...), not a full URL path like /api/v1/files/{id}/content. This caused the function to return the raw file ID unchanged, which is not valid image data for the editing API.

Changes Made

1. backend/open_webui/utils/middleware.py

Updated get_images_from_messages() to also check for content_type starting with 'image/':

Before

if file.get("type") == "image":

After

if file.get("type") == "image" or (
    file.get("content_type") or ""
).startswith("image/"):

2. backend/open_webui/routers/images.py

Updated load_url_image() to handle raw file IDs by attempting to retrieve the file content:

elif data.startswith("data:"):
    # Already base64 encoded, return as-is
    return data

else:
    # Assume it's a raw file ID (frontend sends file.url = file_id)
    try:
        file_response = await get_file_content_by_id(data, user)
        if isinstance(file_response, FileResponse):
            # Read file and convert to base64
            ...
    except Exception:
        pass

How to Test

  1. Start Open WebUI with image editing enabled (configure ENABLE_IMAGE_EDIT=true and set up an image edit engine like Gemini)
  2. Create a new chat (not temporary)
  3. Upload an image (PNG, JPG, etc.)
  4. Turn on the image generation feature toggle
  5. Send a prompt asking to edit the image (e.g., "Add a red hat to the person in this image")
  6. Expected: The uploaded image should be edited according to the prompt
  7. Before fix: A random new image would be generated, ignoring the uploaded image

Additional Notes

  • This fix is backward compatible - it still handles the old type: 'image' format for temporary chats where images are stored as base64 data URLs
  • The fix aligns the backend logic with the existing frontend logic in Chat.svelte that already correctly identifies images using both type and content_type

Fixes #20237

Contributor License Agreement

By submitting this pull request, I confirm that I have read and fully agree to the Contributor License Agreement (CLA), and I am providing my contributions under its terms.

Note

Deleting the CLA section will lead to immediate closure of your PR and it will not be merged in.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/open-webui/open-webui/pull/20238 **Author:** [@Classic298](https://github.com/Classic298) **Created:** 12/29/2025 **Status:** ❌ Closed **Base:** `dev` ← **Head:** `image-edits` --- ### 📝 Commits (10+) - [`2ec1215`](https://github.com/open-webui/open-webui/commit/2ec1215add4c7fe041d59a9ce43ae8641d62e8b7) Add standalone prune script with full prune.py functionality - [`9455912`](https://github.com/open-webui/open-webui/commit/94559127fc9cc66c868951bbf9ea55bbca312db6) Complete modular prune system with interactive UI and comprehensive testing - [`d5442a6`](https://github.com/open-webui/open-webui/commit/d5442a6d72f59a5dab6bd6c79861f11e4989c3a2) Add validation test script for prune system - [`a5b7091`](https://github.com/open-webui/open-webui/commit/a5b7091e5549b93c4f5de28167d7388c4230f2b8) Add Milvus and Milvus Multitenancy vector database cleaners - [`64d0b60`](https://github.com/open-webui/open-webui/commit/64d0b60491a9b3edc7e34f509a7f0fe9c26754d0) Update documentation to reflect Milvus vector database support - [`aa95fa7`](https://github.com/open-webui/open-webui/commit/aa95fa795b3bd4a0e7695a56bfcfcb5e56194816) Add 100% vector database coverage for Milvus multitenancy cleanup - [`61bd9a3`](https://github.com/open-webui/open-webui/commit/61bd9a30aa4bd05881cdac116e8611050a1a3416) Fix Milvus API usage: use utility.drop_collection and add collection.flush() - [`cf356ff`](https://github.com/open-webui/open-webui/commit/cf356ff799475c0fe3c9bcd97d3dd5d0aea61d1b) Add pagination for Milvus multitenancy to handle >16k resources - [`348c128`](https://github.com/open-webui/open-webui/commit/348c128e628d17a307342000ca265844be693cbc) Fix CRITICAL pagination bug: replace offset with query_iterator for Milvus multitenancy - [`fe6783c`](https://github.com/open-webui/open-webui/commit/fe6783c16699911c7be17392596d579333fb110c) Merge pull request #19030 from open-webui/dev ### 📊 Changes **17 files changed** (+6516 additions, -3 deletions) <details> <summary>View changed files</summary> 📝 `backend/open_webui/models/channels.py` (+129 -0) 📝 `backend/open_webui/routers/audio.py` (+1 -1) 📝 `backend/open_webui/routers/files.py` (+1 -1) 📝 `backend/open_webui/routers/images.py` (+21 -0) 📝 `backend/open_webui/utils/middleware.py` (+5 -1) ➕ `prune/README.md` (+502 -0) ➕ `prune/prune.py` (+177 -0) ➕ `prune/prune_cli_interactive.py` (+825 -0) ➕ `prune/prune_core.py` (+1805 -0) ➕ `prune/prune_imports.py` (+185 -0) ➕ `prune/prune_models.py` (+116 -0) ➕ `prune/prune_operations.py` (+644 -0) ➕ `prune/requirements.txt` (+24 -0) ➕ `prune/run_prune.sh` (+95 -0) ➕ `prune/standalone_prune.py` (+826 -0) ➕ `prune/test_prune.py` (+899 -0) ➕ `prune/validate_structure.py` (+261 -0) </details> ### 📄 Description ## Description This PR fixes image editing functionality that broke after the v0.42/v0.43 refactoring which changed how images are stored in chats. Previously, images were stored as base64 data directly in the chat JSON. After the refactor, images are stored as Files in the database and referenced in the chat JSON as URLs (file IDs) for page loading speedup and caching benefits. This change inadvertently broke image editing because the backend code was not updated to handle the new image storage format. ## Root Cause Analysis ### Bug 1: get_images_from_messages only checked type == "image" Location: backend/open_webui/utils/middleware.py The get_images_from_messages function extracts images from chat messages to determine whether to trigger image editing vs image generation. It only checked for `file.get("type") == "image"`. However, when images are uploaded through the file upload API (non-temporary chats), they are stored with: - type: 'file' (not 'image') - content_type: 'image/png' (or other image MIME type) - url: '{file_id}' This caused uploaded images to be completely ignored, resulting in the image generation path being taken instead of image editing. Note: The frontend already correctly handles both cases in Chat.svelte: ``` const imageFiles = (message?.files ?? []).filter( (file) => file.type === 'image' || (file?.content_type ?? '').startsWith('image/') ); ``` ### Bug 2: load_url_image didn't handle raw file IDs Location: backend/open_webui/routers/images.py The load_url_image function in the image_edits endpoint converts image URLs to base64 data before sending to the image editing API. It handled: - URLs starting with http:// or https:// - URLs starting with /api/v1/files - Base64 data URLs (returned as-is) However, when an image is uploaded via the file upload API, the frontend sets file.url to just the file ID (e.g., abc123-def456-...), not a full URL path like /api/v1/files/{id}/content. This caused the function to return the raw file ID unchanged, which is not valid image data for the editing API. ## Changes Made ### 1. backend/open_webui/utils/middleware.py Updated get_images_from_messages() to also check for content_type starting with 'image/': # Before `if file.get("type") == "image":` # After ``` if file.get("type") == "image" or ( file.get("content_type") or "" ).startswith("image/"): ``` ### 2. backend/open_webui/routers/images.py Updated load_url_image() to handle raw file IDs by attempting to retrieve the file content: ``` elif data.startswith("data:"): # Already base64 encoded, return as-is return data else: # Assume it's a raw file ID (frontend sends file.url = file_id) try: file_response = await get_file_content_by_id(data, user) if isinstance(file_response, FileResponse): # Read file and convert to base64 ... except Exception: pass ``` ## How to Test 1. Start Open WebUI with image editing enabled (configure ENABLE_IMAGE_EDIT=true and set up an image edit engine like Gemini) 2. Create a new chat (not temporary) 3. Upload an image (PNG, JPG, etc.) 4. Turn on the image generation feature toggle 5. Send a prompt asking to edit the image (e.g., "Add a red hat to the person in this image") 6. Expected: The uploaded image should be edited according to the prompt 7. Before fix: A random new image would be generated, ignoring the uploaded image ## Additional Notes - This fix is backward compatible - it still handles the old type: 'image' format for temporary chats where images are stored as base64 data URLs - The fix aligns the backend logic with the existing frontend logic in Chat.svelte that already correctly identifies images using both type and content_type Fixes #20237 ### Contributor License Agreement By submitting this pull request, I confirm that I have read and fully agree to the [Contributor License Agreement (CLA)](https://github.com/open-webui/open-webui/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT), and I am providing my contributions under its terms. > [!NOTE] > Deleting the CLA section will lead to immediate closure of your PR and it will not be merged in. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-30 00:34:51 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#48562