chore: import upstream snapshot with attribution
Sync docs with Docusaurus / sync (push) Waiting to run
Tests / Check if changed (push) Waiting to run
Tests / format (push) Blocked by required conditions
Tests / check-imports (push) Blocked by required conditions
Tests / Unit / macos-latest (push) Blocked by required conditions
Tests / Unit / ubuntu-latest (push) Blocked by required conditions
Tests / Unit / windows-latest (push) Blocked by required conditions
Tests / mypy (push) Blocked by required conditions
Tests / Integration / ubuntu-latest (push) Blocked by required conditions
Tests / Integration / macos-latest (push) Blocked by required conditions
Tests / Integration / windows-latest (push) Blocked by required conditions
Tests / notify-slack-on-failure (push) Blocked by required conditions
Tests / Mark tests as completed (push) Blocked by required conditions
Docker image release / Build base image (push) Waiting to run
CodeQL / Analyze (python) (push) Has been cancelled
Update Platform Components Table / update (push) Has been cancelled
Sync docs with Docusaurus / sync (push) Waiting to run
Tests / Check if changed (push) Waiting to run
Tests / format (push) Blocked by required conditions
Tests / check-imports (push) Blocked by required conditions
Tests / Unit / macos-latest (push) Blocked by required conditions
Tests / Unit / ubuntu-latest (push) Blocked by required conditions
Tests / Unit / windows-latest (push) Blocked by required conditions
Tests / mypy (push) Blocked by required conditions
Tests / Integration / ubuntu-latest (push) Blocked by required conditions
Tests / Integration / macos-latest (push) Blocked by required conditions
Tests / Integration / windows-latest (push) Blocked by required conditions
Tests / notify-slack-on-failure (push) Blocked by required conditions
Tests / Mark tests as completed (push) Blocked by required conditions
Docker image release / Build base image (push) Waiting to run
CodeQL / Analyze (python) (push) Has been cancelled
Update Platform Components Table / update (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,413 @@
|
||||
---
|
||||
title: "ChatMessage"
|
||||
id: chatmessage
|
||||
slug: "/chatmessage"
|
||||
description: "`ChatMessage` is the central abstraction to represent a message for a LLM. It contains role, metadata and several types of content, including text, images, tool calls, tool call results, and reasoning content."
|
||||
---
|
||||
|
||||
# ChatMessage
|
||||
|
||||
`ChatMessage` is the central abstraction to represent a message for a LLM. It contains role, metadata and several types of content, including text, images, tool calls, tool call results, and reasoning content.
|
||||
|
||||
To create a `ChatMessage` instance, use `from_user`, `from_system`, `from_assistant`, and `from_tool` class methods.
|
||||
|
||||
The [content](#types-of-content) of the `ChatMessage` can then be inspected using the `text`, `texts`, `image`, `images`, `file`, `files`, `tool_call`, `tool_calls`, `tool_call_result`, `tool_call_results`, `reasoning`, and `reasonings` properties.
|
||||
|
||||
If you are looking for the details of this data class methods and parameters, head over to our [API documentation](/reference/data-classes-api#chatmessage).
|
||||
|
||||
## Types of Content
|
||||
|
||||
`ChatMessage` currently supports `TextContent`, `ImageContent`, `FileContent`, `ToolCall`, `ToolCallResult`, and `ReasoningContent` types of content:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class TextContent:
|
||||
"""
|
||||
The textual content of a chat message.
|
||||
|
||||
:param text: The text content of the message.
|
||||
"""
|
||||
|
||||
text: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class ToolCall:
|
||||
"""
|
||||
Represents a Tool call prepared by the model, usually contained in an assistant message.
|
||||
|
||||
:param tool_name: The name of the Tool to call.
|
||||
:param arguments: The arguments to call the Tool with.
|
||||
:param id: The ID of the Tool call.
|
||||
:param extra: Dictionary of extra information about the Tool call. Use to store provider-specific
|
||||
information. To avoid serialization issues, values should be JSON serializable.
|
||||
"""
|
||||
|
||||
tool_name: str
|
||||
arguments: Dict[str, Any]
|
||||
id: Optional[str] = None # noqa: A003
|
||||
extra: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class ToolCallResult:
|
||||
"""
|
||||
Represents the result of a Tool invocation.
|
||||
|
||||
:param result: The result of the Tool invocation.
|
||||
:param origin: The Tool call that produced this result.
|
||||
:param error: Whether the Tool invocation resulted in an error.
|
||||
"""
|
||||
|
||||
result: str | Sequence[TextContent | ImageContent]
|
||||
origin: ToolCall
|
||||
error: bool
|
||||
|
||||
|
||||
@dataclass
|
||||
class ImageContent:
|
||||
"""
|
||||
The image content of a chat message.
|
||||
|
||||
:param base64_image: A base64 string representing the image.
|
||||
:param mime_type: The MIME type of the image (e.g. "image/png", "image/jpeg").
|
||||
Providing this value is recommended, as most LLM providers require it.
|
||||
If not provided, the MIME type is guessed from the base64 string, which can be slow and not always reliable.
|
||||
:param detail: Optional detail level of the image (only supported by OpenAI). One of "auto", "high", or "low".
|
||||
:param meta: Optional metadata for the image.
|
||||
:param validation: If True (default), a validation process is performed:
|
||||
- Check whether the base64 string is valid;
|
||||
- Guess the MIME type if not provided;
|
||||
- Check if the MIME type is a valid image MIME type.
|
||||
Set to False to skip validation and speed up initialization.
|
||||
"""
|
||||
|
||||
base64_image: str
|
||||
mime_type: Optional[str] = None
|
||||
detail: Optional[Literal["auto", "high", "low"]] = None
|
||||
meta: Dict[str, Any] = field(default_factory=dict)
|
||||
validation: bool = True
|
||||
|
||||
|
||||
@dataclass
|
||||
class FileContent:
|
||||
"""
|
||||
The file content of a chat message.
|
||||
|
||||
:param base64_data: A base64 string representing the file.
|
||||
:param mime_type: The MIME type of the file (e.g. "application/pdf").
|
||||
Providing this value is recommended, as most LLM providers require it.
|
||||
If not provided, the MIME type is guessed from the base64 string, which can be slow and not always reliable.
|
||||
:param filename: Optional filename of the file. Some LLM providers use this information.
|
||||
:param extra: Dictionary of extra information about the file. Can be used to store provider-specific information.
|
||||
To avoid serialization issues, values should be JSON serializable.
|
||||
:param validation: If True (default), a validation process is performed:
|
||||
- Check whether the base64 string is valid;
|
||||
- Guess the MIME type if not provided.
|
||||
Set to False to skip validation and speed up initialization.
|
||||
"""
|
||||
|
||||
base64_data: str
|
||||
mime_type: str | None = None
|
||||
filename: str | None = None
|
||||
extra: dict[str, Any] = field(default_factory=dict)
|
||||
validation: bool = True
|
||||
|
||||
|
||||
@dataclass
|
||||
class ReasoningContent:
|
||||
"""
|
||||
Represents the optional reasoning content prepared by the model, usually contained in an assistant message.
|
||||
|
||||
:param reasoning_text: The reasoning text produced by the model.
|
||||
:param extra: Dictionary of extra information about the reasoning content. Use to store provider-specific
|
||||
information. To avoid serialization issues, values should be JSON serializable.
|
||||
"""
|
||||
|
||||
reasoning_text: str
|
||||
extra: Dict[str, Any] = field(default_factory=dict)
|
||||
```
|
||||
|
||||
The `ImageContent` and `FileContent` dataclasses also provide two convenience class methods: `from_file_path` and `from_url`.
|
||||
For more details, refer to our [API documentation](/reference/data-classes-api).
|
||||
|
||||
## Working with a ChatMessage
|
||||
|
||||
The following examples demonstrate how to create a `ChatMessage` and inspect its properties.
|
||||
|
||||
### from_user with TextContent
|
||||
|
||||
```python
|
||||
from haystack.dataclasses import ChatMessage
|
||||
|
||||
user_message = ChatMessage.from_user("What is the capital of Australia?")
|
||||
|
||||
print(user_message)
|
||||
>>> ChatMessage(
|
||||
>>> _role=<ChatRole.USER: 'user'>,
|
||||
>>> _content=[TextContent(text='What is the capital of Australia?')],
|
||||
>>> _name=None,
|
||||
>>> _meta={}
|
||||
>>>)
|
||||
|
||||
print(user_message.text)
|
||||
>>> What is the capital of Australia?
|
||||
|
||||
print(user_message.texts)
|
||||
>>> ['What is the capital of Australia?']
|
||||
```
|
||||
|
||||
### from_user with TextContent and ImageContent
|
||||
|
||||
```python
|
||||
from haystack.dataclasses import ChatMessage, ImageContent
|
||||
|
||||
lion_image_url = (
|
||||
"https://images.unsplash.com/photo-1546182990-dffeafbe841d?"
|
||||
"ixlib=rb-4.0&q=80&w=1080&fit=max"
|
||||
)
|
||||
|
||||
image_content = ImageContent.from_url(lion_image_url, detail="low")
|
||||
|
||||
user_message = ChatMessage.from_user(
|
||||
content_parts=[
|
||||
"What does the image show?",
|
||||
image_content
|
||||
])
|
||||
|
||||
print(user_message)
|
||||
>>> ChatMessage(
|
||||
>>> _role=<ChatRole.USER: 'user'>,
|
||||
>>> _content=[
|
||||
>>> TextContent(text='What does the image show?'),
|
||||
>>> ImageContent(
|
||||
>>> base64_image='/9j/4...',
|
||||
>>> mime_type='image/jpeg',
|
||||
>>> detail='low',
|
||||
>>> meta={
|
||||
>>> 'content_type': 'image/jpeg',
|
||||
>>> 'url': '...'
|
||||
>>> }
|
||||
>>> )
|
||||
>>> ],
|
||||
>>> _name=None,
|
||||
>>> _meta={}
|
||||
>>> )
|
||||
|
||||
print(user_message.text)
|
||||
>>> What does the image show?
|
||||
|
||||
print(user_message.texts)
|
||||
>>> ['What does the image show?']
|
||||
|
||||
print(user_message.image)
|
||||
>>> ImageContent(
|
||||
>>> base64_image='/9j/4...',
|
||||
>>> mime_type='image/jpeg',
|
||||
>>> detail='low',
|
||||
>>> meta={
|
||||
>>> 'content_type': 'image/jpeg',
|
||||
>>> 'url': '...'
|
||||
>>> }
|
||||
>>> )
|
||||
```
|
||||
|
||||
### from_user with TextContent and FileContent
|
||||
|
||||
```python
|
||||
from haystack.dataclasses import ChatMessage, FileContent
|
||||
|
||||
paper_url = "https://arxiv.org/pdf/2309.08632"
|
||||
|
||||
file_content = FileContent.from_url(paper_url)
|
||||
|
||||
user_message = ChatMessage.from_user(
|
||||
content_parts=[
|
||||
file_content,
|
||||
"Summarize this paper in 100 words."
|
||||
])
|
||||
|
||||
print(user_message)
|
||||
>>> ChatMessage(
|
||||
>>> _role=<ChatRole.USER: 'user'>,
|
||||
>>> _content=[
|
||||
>>> FileContent(
|
||||
>>> base64_data='JVBERi0...',
|
||||
>>> mime_type='application/pdf',
|
||||
>>> filename='2309.08632',
|
||||
>>> extra={}
|
||||
>>> ),
|
||||
>>> TextContent(text='Summarize this paper in 100 words.')
|
||||
>>> ],
|
||||
>>> _name=None,
|
||||
>>> _meta={}
|
||||
>>> )
|
||||
|
||||
print(user_message.text)
|
||||
>>> Summarize this paper in 100 words.
|
||||
|
||||
print(user_message.texts)
|
||||
>>> ['Summarize this paper in 100 words.']
|
||||
|
||||
print(user_message.file)
|
||||
>>> FileContent(
|
||||
>>> base64_data='JVBERi0...',
|
||||
>>> mime_type='application/pdf',
|
||||
>>> filename='2309.08632',
|
||||
>>> extra={}
|
||||
>>> )
|
||||
```
|
||||
|
||||
### from_assistant with TextContent
|
||||
|
||||
```python
|
||||
from haystack.dataclasses import ChatMessage
|
||||
|
||||
assistant_message = ChatMessage.from_assistant("How can I assist you today?")
|
||||
|
||||
print(assistant_message)
|
||||
>>> ChatMessage(
|
||||
>>> _role=<ChatRole.ASSISTANT: 'assistant'>,
|
||||
>>> _content=[TextContent(text='How can I assist you today?')],
|
||||
>>> _name=None,
|
||||
>>> _meta={}
|
||||
>>>)
|
||||
|
||||
print(assistant_message.text)
|
||||
>>> How can I assist you today?
|
||||
|
||||
print(assistant_message.texts)
|
||||
>>> ['How can I assist you today?']
|
||||
```
|
||||
|
||||
### from_assistant with ToolCall
|
||||
|
||||
```python
|
||||
from haystack.dataclasses import ChatMessage, ToolCall
|
||||
|
||||
tool_call = ToolCall(tool_name="weather_tool", arguments={"location": "Rome"})
|
||||
|
||||
assistant_message_w_tool_call = ChatMessage.from_assistant(tool_calls=[tool_call])
|
||||
|
||||
print(assistant_message_w_tool_call)
|
||||
>>> ChatMessage(
|
||||
>>> _role=<ChatRole.ASSISTANT: 'assistant'>,
|
||||
>>> _content=[ToolCall(tool_name='weather_tool', arguments={'location': 'Rome'}, id=None)],
|
||||
>>> _name=None,
|
||||
>>> _meta={}
|
||||
>>>)
|
||||
|
||||
print(assistant_message_w_tool_call.text)
|
||||
>>> None
|
||||
|
||||
print(assistant_message_w_tool_call.texts)
|
||||
>>> []
|
||||
|
||||
print(assistant_message_w_tool_call.tool_call)
|
||||
>>> ToolCall(tool_name='weather_tool', arguments={'location': 'Rome'}, id=None)
|
||||
|
||||
print(assistant_message_w_tool_call.tool_calls)
|
||||
>>> [ToolCall(tool_name='weather_tool', arguments={'location': 'Rome'}, id=None)]
|
||||
|
||||
print(assistant_message_w_tool_call.tool_call_result)
|
||||
>>> None
|
||||
|
||||
print(assistant_message_w_tool_call.tool_call_results)
|
||||
>>> []
|
||||
```
|
||||
|
||||
### from_tool
|
||||
|
||||
```python
|
||||
from haystack.dataclasses import ChatMessage
|
||||
|
||||
tool_message = ChatMessage.from_tool(tool_result="temperature: 25°C", origin=tool_call, error=False)
|
||||
|
||||
print(tool_message)
|
||||
>>> ChatMessage(
|
||||
>>> _role=<ChatRole.TOOL: 'tool'>,
|
||||
>>> _content=[ToolCallResult(
|
||||
>>> result='temperature: 25°C',
|
||||
>>> origin=ToolCall(tool_name='weather_tool', arguments={'location': 'Rome'}, id=None),
|
||||
>>> error=False
|
||||
>>> )],
|
||||
>>> _name=None,
|
||||
>>> _meta={}
|
||||
>>>)
|
||||
|
||||
print(tool_message.text)
|
||||
>>> None
|
||||
|
||||
print(tool_message.texts)
|
||||
>>> []
|
||||
|
||||
print(tool_message.tool_call)
|
||||
>>> None
|
||||
|
||||
print(tool_message.tool_calls)
|
||||
>>> []
|
||||
|
||||
print(tool_message.tool_call_result)
|
||||
>>> ToolCallResult(
|
||||
>>> result='temperature: 25°C',
|
||||
>>> origin=ToolCall(tool_name='weather_tool', arguments={'location': 'Rome'}, id=None),
|
||||
>>> error=False
|
||||
>>> )
|
||||
|
||||
print(tool_message.tool_call_results)
|
||||
>>> [
|
||||
>>> ToolCallResult(
|
||||
>>> result='temperature: 25°C',
|
||||
>>> origin=ToolCall(tool_name='weather_tool', arguments={'location': 'Rome'}, id=None),
|
||||
>>> error=False
|
||||
>>> )
|
||||
>>> ]
|
||||
```
|
||||
|
||||
## Migrating from Legacy ChatMessage (before v2.9)
|
||||
|
||||
In Haystack 2.9, we updated the `ChatMessage` data class for greater flexibility and support for multiple content types: text, tool calls, and tool call results.
|
||||
|
||||
There are some breaking changes involved, so we recommend reviewing this guide to migrate smoothly.
|
||||
|
||||
### Creating a ChatMessage
|
||||
|
||||
You can no longer directly initialize `ChatMessage` using `role`, `content`, and `meta`.
|
||||
|
||||
- Use the following class methods instead: `from_assistant`, `from_user`, `from_system`, and `from_tool`.
|
||||
- Replace the `content` parameter with `text`.
|
||||
|
||||
```python
|
||||
from haystack.dataclasses import ChatMessage
|
||||
|
||||
# LEGACY - DOES NOT WORK IN 2.9.0
|
||||
message = ChatMessage(role=ChatRole.USER, content="Hello!")
|
||||
|
||||
# Use the class method instead
|
||||
message = ChatMessage.from_user("Hello!")
|
||||
```
|
||||
|
||||
### Accessing ChatMessage Attributes
|
||||
|
||||
- The legacy `content` attribute is now internal (`_content`).
|
||||
- Inspect `ChatMessage` attributes using the following properties:
|
||||
- `role`
|
||||
- `meta`
|
||||
- `name`
|
||||
- `text` and `texts`
|
||||
- `image` and `images`
|
||||
- `tool_call` and `tool_calls`
|
||||
- `tool_call_result` and `tool_call_results`
|
||||
- `reasoning` and `reasonings`
|
||||
|
||||
```python
|
||||
from haystack.dataclasses import ChatMessage
|
||||
|
||||
message = ChatMessage.from_user("Hello!")
|
||||
|
||||
# LEGACY - DOES NOT WORK IN 2.9.0
|
||||
print(message.content)
|
||||
|
||||
# Use the appropriate property instead
|
||||
print(message.text)
|
||||
```
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: "FileContent"
|
||||
id: filecontent
|
||||
slug: "/filecontent"
|
||||
description: "`FileContent` represents file payloads in chat messages, including base64 data, MIME type, filename, and provider-specific metadata."
|
||||
---
|
||||
|
||||
# FileContent
|
||||
|
||||
`FileContent` represents a file payload that can be attached to a [`ChatMessage`](chatmessage.mdx). Use it when a chat model accepts file inputs, such as PDFs or other documents, together with the user's text prompt.
|
||||
|
||||
If you need the full list of parameters and methods, see the [`FileContent` API reference](/reference/data-classes-api#filecontent).
|
||||
|
||||
## Attributes
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class FileContent:
|
||||
base64_data: str
|
||||
mime_type: str | None = None
|
||||
filename: str | None = None
|
||||
extra: dict[str, Any] = field(default_factory=dict)
|
||||
validation: bool = True
|
||||
```
|
||||
|
||||
- `base64_data` stores the file content as a base64-encoded string.
|
||||
- `mime_type` identifies the file type, for example `application/pdf`. Providing it explicitly is recommended because many model providers require it.
|
||||
- `filename` is optional, but some providers use it when processing uploaded files.
|
||||
- `extra` can store provider-specific metadata. Values should be JSON serializable.
|
||||
- `validation` checks that `base64_data` is valid and tries to infer the MIME type when one is not provided.
|
||||
|
||||
## Create from a file path
|
||||
|
||||
Use `from_file_path` to read a local file, base64-encode it, infer the MIME type from the path, and populate the filename.
|
||||
|
||||
```python
|
||||
from haystack.dataclasses import ChatMessage, FileContent
|
||||
|
||||
file_content = FileContent.from_file_path("data/attention-is-all-you-need.pdf")
|
||||
|
||||
message = ChatMessage.from_user(
|
||||
content_parts=[
|
||||
file_content,
|
||||
"Summarize the key ideas in this paper.",
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
Pass `filename` or `extra` when a provider expects a specific filename or provider-specific options:
|
||||
|
||||
```python
|
||||
file_content = FileContent.from_file_path(
|
||||
"data/report.pdf",
|
||||
filename="quarterly-report.pdf",
|
||||
extra={"source": "finance"},
|
||||
)
|
||||
```
|
||||
|
||||
## Create from a URL
|
||||
|
||||
Use `from_url` to download a file and convert it into a `FileContent` instance.
|
||||
|
||||
```python
|
||||
from haystack.dataclasses import FileContent
|
||||
|
||||
file_content = FileContent.from_url(
|
||||
"https://example.com/reports/quarterly-report.pdf",
|
||||
timeout=30,
|
||||
)
|
||||
```
|
||||
|
||||
If no filename is provided, Haystack uses the final path segment of the URL.
|
||||
|
||||
## Create from base64 data
|
||||
|
||||
If you already have file bytes, encode them and pass the MIME type explicitly.
|
||||
|
||||
```python
|
||||
import base64
|
||||
from pathlib import Path
|
||||
|
||||
from haystack.dataclasses import FileContent
|
||||
|
||||
data = Path("data/manual.pdf").read_bytes()
|
||||
file_content = FileContent(
|
||||
base64_data=base64.b64encode(data).decode("utf-8"),
|
||||
mime_type="application/pdf",
|
||||
filename="manual.pdf",
|
||||
)
|
||||
```
|
||||
|
||||
Set `validation=False` only when the base64 data and MIME type are already trusted and you want to skip validation.
|
||||
|
||||
## Inspect files in a ChatMessage
|
||||
|
||||
After adding `FileContent` to a `ChatMessage`, use the `file` and `files` properties to access file payloads.
|
||||
|
||||
```python
|
||||
from haystack.dataclasses import ChatMessage, FileContent
|
||||
|
||||
file_content = FileContent.from_file_path("data/invoice.pdf")
|
||||
message = ChatMessage.from_user(content_parts=[file_content, "Extract the invoice total."])
|
||||
|
||||
print(message.file)
|
||||
print(message.files)
|
||||
```
|
||||
|
||||
`message.file` returns the first file payload, or `None` if there are no files. `message.files` returns all file payloads.
|
||||
|
||||
## Serialization
|
||||
|
||||
Use `to_dict` and `from_dict` to serialize and restore file content.
|
||||
|
||||
```python
|
||||
payload = file_content.to_dict()
|
||||
restored = FileContent.from_dict(payload)
|
||||
```
|
||||
|
||||
For tracing, Haystack replaces the full base64 payload with a placeholder so large files are not sent to the tracing backend.
|
||||
@@ -0,0 +1,247 @@
|
||||
---
|
||||
title: "ImageContent"
|
||||
id: imagecontent
|
||||
slug: "/imagecontent"
|
||||
description: "`ImageContent` represents image-based content in Haystack chat messages and multimodal pipelines."
|
||||
---
|
||||
|
||||
# ImageContent
|
||||
|
||||
`ImageContent` is a Haystack data class used to represent image-based content in chat messages and multimodal AI pipelines.
|
||||
|
||||
It is commonly used with:
|
||||
|
||||
* multimodal LLMs
|
||||
* vision-language models
|
||||
* image-aware chat applications
|
||||
* document/image processing workflows
|
||||
|
||||
`ImageContent` stores images as base64-encoded strings together with metadata such as MIME type and image detail level.
|
||||
|
||||
If you are looking for the full API reference, see the [API documentation](/reference/data-classes-api#imagecontent).
|
||||
|
||||
---
|
||||
|
||||
# Creating ImageContent
|
||||
|
||||
You can create an `ImageContent` object directly from a base64 string:
|
||||
|
||||
```python
|
||||
from haystack.dataclasses import ImageContent
|
||||
|
||||
image = ImageContent(base64_image="your_base64_encoded_image", mime_type="image/png")
|
||||
|
||||
print(image)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Loading Images from a File Path
|
||||
|
||||
The `from_file_path()` class method provides a convenient way to load local image files.
|
||||
|
||||
```python
|
||||
from haystack.dataclasses import ImageContent
|
||||
|
||||
image = ImageContent.from_file_path("sample.png", detail="low")
|
||||
|
||||
print(image)
|
||||
```
|
||||
|
||||
The optional `detail` parameter is currently supported by OpenAI vision models and accepts:
|
||||
|
||||
* `"auto"`
|
||||
* `"high"`
|
||||
* `"low"`
|
||||
|
||||
You can also resize images while loading:
|
||||
|
||||
```python
|
||||
image = ImageContent.from_file_path("sample.png", size=(512, 512))
|
||||
```
|
||||
|
||||
This helps reduce:
|
||||
|
||||
* memory usage
|
||||
* processing time
|
||||
* payload size
|
||||
|
||||
when working with multimodal LLM APIs.
|
||||
|
||||
---
|
||||
|
||||
# Loading Images from a URL
|
||||
|
||||
You can also create an `ImageContent` object directly from an image URL:
|
||||
|
||||
```python
|
||||
from haystack.dataclasses import ImageContent
|
||||
|
||||
image = ImageContent.from_url(
|
||||
"https://images.unsplash.com/photo-1546182990-dffeafbe841d",
|
||||
detail="low",
|
||||
)
|
||||
|
||||
print(image)
|
||||
```
|
||||
|
||||
Internally, Haystack downloads the image and converts it into a base64 representation.
|
||||
|
||||
---
|
||||
|
||||
# Producing ImageContent with Converters
|
||||
|
||||
In a pipeline, you usually don't create `ImageContent` objects by hand. Instead, you use converter components that read files and produce `ImageContent` for you:
|
||||
|
||||
* [`ImageFileToImageContent`](../../pipeline-components/converters/imagefiletoimagecontent.mdx) converts local image files (such as PNG or JPEG) into `ImageContent` objects.
|
||||
* [`PDFToImageContent`](../../pipeline-components/converters/pdftoimagecontent.mdx) renders the pages of PDF files into `ImageContent` objects.
|
||||
|
||||
```python
|
||||
from haystack.components.converters.image import (
|
||||
ImageFileToImageContent,
|
||||
PDFToImageContent,
|
||||
)
|
||||
|
||||
image_converter = ImageFileToImageContent()
|
||||
image_contents = image_converter.run(sources=["image.jpg", "another_image.png"])[
|
||||
"image_contents"
|
||||
]
|
||||
|
||||
pdf_converter = PDFToImageContent()
|
||||
pdf_image_contents = pdf_converter.run(sources=["file.pdf"])["image_contents"]
|
||||
```
|
||||
|
||||
Both converters accept the optional `detail` and `size` parameters, which are forwarded to the `ImageContent` objects they create.
|
||||
|
||||
---
|
||||
|
||||
# Using ImageContent with ChatMessage
|
||||
|
||||
`ImageContent` is commonly used together with [`ChatMessage`](chatmessage.mdx) for multimodal conversations.
|
||||
|
||||
```python
|
||||
from haystack.dataclasses import ChatMessage, ImageContent
|
||||
|
||||
image = ImageContent.from_url(
|
||||
"https://images.unsplash.com/photo-1546182990-dffeafbe841d",
|
||||
detail="low",
|
||||
)
|
||||
|
||||
message = ChatMessage.from_user(content_parts=["What does this image show?", image])
|
||||
|
||||
print(message)
|
||||
```
|
||||
|
||||
This allows multimodal LLMs to process both:
|
||||
|
||||
* textual prompts
|
||||
* image inputs
|
||||
|
||||
within the same message.
|
||||
|
||||
For more dynamic prompts, you can build multimodal messages with [`ChatPromptBuilder`](../../pipeline-components/builders/chatpromptbuilder.mdx) using Jinja2 string templates. The `| templatize_part` filter inserts an `ImageContent` object as a structured content part instead of plain text:
|
||||
|
||||
```python
|
||||
from haystack.components.builders import ChatPromptBuilder
|
||||
from haystack.dataclasses import ChatMessage, ImageContent
|
||||
|
||||
template = """
|
||||
{% message role="user" %}
|
||||
Hello! I am {{user_name}}. What's the difference between the following images?
|
||||
{% for image in images %}
|
||||
{{ image | templatize_part }}
|
||||
{% endfor %}
|
||||
{% endmessage %}
|
||||
"""
|
||||
|
||||
builder = ChatPromptBuilder(template=template)
|
||||
images = [
|
||||
ImageContent.from_file_path("apple.jpg"),
|
||||
ImageContent.from_file_path("kiwi.jpg"),
|
||||
]
|
||||
result = builder.run(user_name="John", images=images)
|
||||
|
||||
print(result["prompt"])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Metadata
|
||||
|
||||
The optional `meta` parameter allows you to attach custom metadata to the image.
|
||||
|
||||
```python
|
||||
image = ImageContent.from_url(
|
||||
"https://images.unsplash.com/photo-1546182990-dffeafbe841d",
|
||||
meta={"source": "example-dataset"},
|
||||
)
|
||||
```
|
||||
|
||||
This can be useful for:
|
||||
|
||||
* tracing
|
||||
* dataset tracking
|
||||
* workflow metadata
|
||||
* custom application logic
|
||||
|
||||
---
|
||||
|
||||
# Validation
|
||||
|
||||
By default, `ImageContent` validates:
|
||||
|
||||
* base64 encoding
|
||||
* MIME type correctness
|
||||
* image MIME compatibility
|
||||
|
||||
Validation can be disabled to improve performance:
|
||||
|
||||
```python
|
||||
image = ImageContent(
|
||||
base64_image="your_base64_encoded_image",
|
||||
mime_type="image/png",
|
||||
validation=False,
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Serialization
|
||||
|
||||
`ImageContent` supports dictionary serialization.
|
||||
|
||||
```python
|
||||
image_dict = image.to_dict()
|
||||
|
||||
restored_image = ImageContent.from_dict(image_dict)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Displaying Images
|
||||
|
||||
The `show()` method can display images directly in:
|
||||
|
||||
* Jupyter notebooks
|
||||
* local desktop environments
|
||||
|
||||
```python
|
||||
image.show()
|
||||
```
|
||||
|
||||
This requires the `Pillow` package:
|
||||
|
||||
```bash
|
||||
pip install pillow
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Related Components
|
||||
|
||||
`ImageContent` is frequently used with:
|
||||
|
||||
* [`ChatMessage`](chatmessage.mdx) — to build multimodal messages
|
||||
* [`ChatPromptBuilder`](../../pipeline-components/builders/chatpromptbuilder.mdx) — to template multimodal prompts
|
||||
* [`ImageFileToImageContent`](../../pipeline-components/converters/imagefiletoimagecontent.mdx) — to convert image files into `ImageContent`
|
||||
* [`PDFToImageContent`](../../pipeline-components/converters/pdftoimagecontent.mdx) — to convert PDF pages into `ImageContent`
|
||||
Reference in New Issue
Block a user