This commit is contained in:
Classic298 2026-09-12 16:19:26 -05:00 committed by GitHub
commit f129803c9c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 37 additions and 6 deletions

View file

@ -32,6 +32,7 @@ from open_webui.storage.provider import Storage
BASE64_IMAGE_URL_PREFIX = re.compile(r'data:image/\w+;base64,', re.IGNORECASE)
MARKDOWN_IMAGE_URL_PATTERN = re.compile(r'!\[(.*?)\]\((.+?)\)', re.IGNORECASE)
FILE_CONTENT_URL_PATTERN = re.compile(r'^/api/v1/files/([^/?#]+)/content')
# Extension-based MIME fallback, only used when ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK is True.
_IMAGE_MIME_FALLBACK = {
@ -90,7 +91,8 @@ async def get_image_base64_from_url(url: str, user=None) -> Optional[str]:
else:
# Non-URL string — treat as file_id. Delegate to the canonical
# file-ID resolver which enforces ownership/access checks.
return await get_image_base64_from_file_id(url, user=user)
file_id_match = FILE_CONTENT_URL_PATTERN.match(url)
return await get_image_base64_from_file_id(file_id_match.group(1) if file_id_match else url, user=user)
except Exception:
return None

View file

@ -976,6 +976,24 @@ async def apply_source_context_to_messages(
)
async def store_tool_result_image(request, image_url, metadata, user):
"""Swap a base64 tool image for a stored file so the chat keeps a reference, not the payload."""
if not isinstance(image_url, str) or not image_url.startswith('data:'):
return image_url
stored_url = await get_file_url_from_base64(
request,
image_url,
{
'chat_id': (metadata or {}).get('chat_id'),
'message_id': (metadata or {}).get('message_id'),
'session_id': (metadata or {}).get('session_id'),
},
user,
)
return stored_url or image_url
async def process_tool_result(
request,
tool_function_name,
@ -1403,6 +1421,11 @@ async def chat_completion_tools_handler(
)
if tool_result_files:
for file_item in tool_result_files:
file_item['url'] = await store_tool_result_image(
request, file_item.get('url'), metadata, user
)
await event_emitter(
{
'type': 'files',
@ -2091,7 +2114,7 @@ async def convert_url_images_to_base64(form_data, user=None):
new_content = []
for item in content:
if not isinstance(item, dict) or item.get('type') != 'image_url':
if not isinstance(item, dict) or item.get('type') not in ('image_url', 'input_image'):
new_content.append(item)
continue
@ -2108,13 +2131,15 @@ async def convert_url_images_to_base64(form_data, user=None):
try:
base64_data = await get_image_base64_from_url(image_url, user=user)
if base64_data:
if base64_data and isinstance(image_url_data, str):
new_content.append({**item, 'image_url': base64_data})
elif base64_data:
image_url_payload = {'url': base64_data}
if isinstance(image_url_data, dict) and image_url_data.get('detail'):
image_url_payload['detail'] = image_url_data['detail']
new_content.append(
{
'type': 'image_url',
'type': item['type'],
'image_url': image_url_payload,
}
)
@ -3294,7 +3319,8 @@ async def drain_approved_tool_calls(request, form_data, user, model, metadata) -
display_files = []
for file_item in result.get('files', []):
if file_item.get('type') == 'image' and file_item.get('url', '').startswith('data:'):
output_parts.append({'type': 'input_image', 'image_url': file_item['url']})
image_url = await store_tool_result_image(request, file_item['url'], metadata, user)
output_parts.append({'type': 'input_image', 'image_url': image_url})
else:
display_files.append(file_item)
@ -5869,7 +5895,8 @@ async def streaming_chat_response_handler(response, ctx):
for file_item in result.get('files', []):
if file_item.get('type') == 'image' and file_item.get('url', '').startswith('data:'):
# LLM-only: add as input_image part, not frontend display output.
output_parts.append({'type': 'input_image', 'image_url': file_item['url']})
image_url = await store_tool_result_image(request, file_item['url'], metadata, user)
output_parts.append({'type': 'input_image', 'image_url': image_url})
else:
# Frontend display (MCP images, audio, etc.)
display_files.append(file_item)
@ -6033,6 +6060,8 @@ async def streaming_chat_response_handler(response, ctx):
}
)
new_form_data = await convert_url_images_to_base64(new_form_data, user=user)
if filter_functions:
new_form_data, _ = await process_filter_functions(
request=request,