Files
microsoft--agent-lightning/examples/chartqa/multimodal_utils.py
T
wehub-resource-sync 85742ab165
Deploy Documentation / deploy (push) Has been cancelled
CPU Test / Test (Utilities, legacy, Python 3.10) (push) Has been cancelled
CPU Test / Test (LLM proxy, stable, Python 3.11) (push) Has been cancelled
CPU Test / Test (Others, stable, Python 3.11) (push) Has been cancelled
CPU Test / Test (Store, stable, Python 3.11) (push) Has been cancelled
CPU Test / Test (Utilities, stable, Python 3.11) (push) Has been cancelled
CPU Test / Test (Weave, stable, Python 3.11) (push) Has been cancelled
CPU Test / Test (AgentOps, stable, Python 3.12) (push) Has been cancelled
CPU Test / Test (LLM proxy, stable, Python 3.12) (push) Has been cancelled
CPU Test / Test (Others, stable, Python 3.12) (push) Has been cancelled
CPU Test / Test (Weave, latest, Python 3.13) (push) Has been cancelled
Dashboard / Chromatic (push) Has been cancelled
CPU Test / Lint - fast (push) Has been cancelled
CPU Test / Lint - next (push) Has been cancelled
CPU Test / Lint - slow (push) Has been cancelled
CPU Test / Lint - JavaScript (push) Has been cancelled
CPU Test / Build documentation (push) Has been cancelled
CPU Test / Test (AgentOps, legacy, Python 3.10) (push) Has been cancelled
CPU Test / Test (LLM proxy, legacy, Python 3.10) (push) Has been cancelled
CPU Test / Test (Others, legacy, Python 3.10) (push) Has been cancelled
CPU Test / Test (Store, legacy, Python 3.10) (push) Has been cancelled
CPU Test / Test (Weave, legacy, Python 3.10) (push) Has been cancelled
CPU Test / Test (AgentOps, stable, Python 3.11) (push) Has been cancelled
CPU Test / Test (Store, stable, Python 3.12) (push) Has been cancelled
CPU Test / Test (Utilities, stable, Python 3.12) (push) Has been cancelled
CPU Test / Test (Weave, stable, Python 3.12) (push) Has been cancelled
CPU Test / Test (AgentOps, latest, Python 3.13) (push) Has been cancelled
CPU Test / Test (LLM proxy, latest, Python 3.13) (push) Has been cancelled
CPU Test / Test (Others, latest, Python 3.13) (push) Has been cancelled
CPU Test / Test (Store, latest, Python 3.13) (push) Has been cancelled
CPU Test / Test (Utilities, latest, Python 3.13) (push) Has been cancelled
CPU Test / Test (JavaScript) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:44:17 +08:00

114 lines
3.3 KiB
Python

# Copyright (c) Microsoft. All rights reserved.
"""
Multimodal support utilities for Agent Lightning.
This module provides helper functions for working with multimodal agents,
particularly for vision-language tasks.
"""
from __future__ import annotations
import base64
from io import BytesIO
from pathlib import Path
from typing import Any, Union
import requests
from PIL import Image
from PIL.Image import Image as PILImage
__all__ = [
"encode_image_to_base64",
"create_image_message",
]
def encode_image_to_base64(image: Union[str, Path, PILImage], max_size: int = 2048) -> str:
"""
Encode an image to base64 string for multimodal LLM APIs.
Args:
image: Image source (file path, URL, or PIL Image object)
max_size: Maximum dimension for resizing
Returns:
Base64 encoded image string with data URI prefix
Raises:
ImportError: If PIL (Pillow) is not installed
TypeError: If image type is not supported
Examples:
>>> encoded = encode_image_to_base64("photo.jpg")
>>> encoded[:30]
'data:image/jpeg;base64,/9j/4A...'
>>> from PIL import Image
>>> img = Image.open("photo.jpg")
>>> encoded = encode_image_to_base64(img)
"""
# Load image
if isinstance(image, (str, Path)):
image_str = str(image)
if image_str.startswith(("http://", "https://")):
response = requests.get(image_str, timeout=30)
response.raise_for_status()
img = Image.open(BytesIO(response.content))
else:
img = Image.open(image_str)
elif hasattr(image, "mode"):
# PIL Image object
img = image
else:
raise TypeError(f"Unsupported image type: {type(image)}")
# Convert to RGB
if img.mode == "RGBA":
background = Image.new("RGB", img.size, (255, 255, 255))
background.paste(img, mask=img.split()[3])
img = background
elif img.mode != "RGB":
img = img.convert("RGB")
# Resize if needed
if max(img.size) > max_size:
img.thumbnail((max_size, max_size), Image.Resampling.LANCZOS)
# Encode
buffered = BytesIO()
img.save(buffered, format="JPEG", quality=85)
img_str = base64.b64encode(buffered.getvalue()).decode()
return f"data:image/jpeg;base64,{img_str}"
def create_image_message(text: str, image: Union[str, Path, PILImage], use_base64: bool = True) -> dict[str, Any]:
"""
Create an OpenAI-compatible multimodal message.
Args:
text: The text prompt/question
image: Image source (path, URL, or PIL Image)
use_base64: If True, encode as base64; if False, use URL directly
Returns:
Message dict with role="user" and multimodal content
Examples:
>>> msg = create_image_message("What's in the image?", "photo.jpg")
>>> msg["role"]
'user'
>>> len(msg["content"])
2
"""
content: list[dict[str, Any]] = [{"type": "text", "text": text}]
if isinstance(image, str) and image.startswith(("http://", "https://")) and not use_base64:
content.append({"type": "image_url", "image_url": {"url": image}})
else:
encoded = encode_image_to_base64(image)
content.append({"type": "image_url", "image_url": {"url": encoded}})
return {"role": "user", "content": content}