Nous.Message.ContentPart (nous v0.9.0)

View Source

Represents a part of message content supporting multi-modal inputs.

ContentPart enables rich message composition with text, images, files, and other content types. Each part has a type and content, with optional provider-specific metadata.

Content Types

  • :text - Plain text content
  • :image_url - Image from URL or data URI
  • :image - Image with base64 data and metadata
  • :file - File attachment
  • :file_url - File from URL
  • :thinking - Reasoning/thinking content (for models that support it)

Examples

# Text content
iex> ContentPart.text("Hello, world!")
%ContentPart{type: :text, content: "Hello, world!", options: %{}}

# Image from URL
iex> ContentPart.image_url("https://example.com/image.jpg")
%ContentPart{type: :image_url, content: "https://example.com/image.jpg", options: %{}}

# Image with metadata
iex> ContentPart.image("base64data", media_type: "image/jpeg")
%ContentPart{type: :image, content: "base64data", options: %{media_type: "image/jpeg"}}

Summary

Functions

Convert base64 string to a data URL.

Detect MIME type from file extension.

Extract text content from a list of content parts.

Create a file content part.

Create a file URL content part.

Create an image content part from binary data with automatic MIME detection.

Create an image content part from a local file path.

Create an image content part from a local file path, raising on error.

Create an image content part with metadata.

Create an image URL content part.

Merge content parts of the same type.

Create a new content part.

Create a new content part, raising on validation failure.

Create a 1x1 pixel test image as base64 data URL.

Create a text content part.

Create a thinking content part for models that support reasoning.

Convert binary image data to a data URL.

Convert content parts to plain text representation.

Types

t()

@type t() :: %Nous.Message.ContentPart{
  content: String.t(),
  options: map(),
  type: atom()
}

Functions

base64_to_data_url(base64_string, mime_type)

@spec base64_to_data_url(String.t(), String.t()) :: String.t()

Convert base64 string to a data URL.

Examples

iex> base64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJ"
iex> ContentPart.base64_to_data_url(base64, "image/png")
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJ"

detect_mime_type(file_path)

@spec detect_mime_type(String.t()) :: String.t()

Detect MIME type from file extension.

Examples

iex> ContentPart.detect_mime_type("/path/to/image.jpg")
"image/jpeg"

iex> ContentPart.detect_mime_type("photo.png")
"image/png"

iex> ContentPart.detect_mime_type("unknown.xyz")
"application/octet-stream"

extract_text(parts)

@spec extract_text([t()]) :: String.t()

Extract text content from a list of content parts.

Examples

iex> parts = [ContentPart.text("Hello"), ContentPart.text(" world")]
iex> ContentPart.extract_text(parts)
"Hello world"

file(path_or_data, opts \\ [])

@spec file(
  String.t(),
  keyword()
) :: t()

Create a file content part.

Examples

iex> ContentPart.file("/path/to/file.pdf", media_type: "application/pdf")
%ContentPart{type: :file, content: "/path/to/file.pdf", options: %{media_type: "application/pdf"}}

file_url(url)

@spec file_url(String.t()) :: t()

Create a file URL content part.

Examples

iex> ContentPart.file_url("https://example.com/document.pdf")
%ContentPart{type: :file_url, content: "https://example.com/document.pdf"}

from_binary(binary_data, filename_hint \\ "image.png")

@spec from_binary(binary(), String.t()) :: t()

Create an image content part from binary data with automatic MIME detection.

Examples

iex> {:ok, image_data} = File.read("photo.jpg")
iex> ContentPart.from_binary(image_data, "photo.jpg")
%ContentPart{type: :image_url, content: "data:image/jpeg;base64,..."}

from_file(file_path)

@spec from_file(String.t()) :: {:ok, t()} | {:error, atom()}

Create an image content part from a local file path.

Reads the file, detects the MIME type, and converts to base64 data URL.

Examples

iex> ContentPart.from_file("/path/to/image.jpg")
{:ok, %ContentPart{type: :image_url, content: "data:image/jpeg;base64,..."}}

iex> ContentPart.from_file("/nonexistent.jpg")
{:error, :enoent}

from_file!(file_path)

@spec from_file!(String.t()) :: t()

Create an image content part from a local file path, raising on error.

Examples

iex> ContentPart.from_file!("/path/to/image.jpg")
%ContentPart{type: :image_url, content: "data:image/jpeg;base64,..."}

image(data, opts \\ [])

@spec image(
  String.t(),
  keyword()
) :: t()

Create an image content part with metadata.

Options

  • :media_type - MIME type (e.g., "image/jpeg", "image/png")
  • :cache_control - Caching hints for providers that support it

Examples

iex> ContentPart.image("base64data", media_type: "image/jpeg")
%ContentPart{type: :image, content: "base64data", options: %{media_type: "image/jpeg"}}

image_url(url)

@spec image_url(String.t()) :: t()

Create an image URL content part.

Examples

iex> ContentPart.image_url("https://example.com/image.jpg")
%ContentPart{type: :image_url, content: "https://example.com/image.jpg"}

iex> ContentPart.image_url("data:image/jpeg;base64,/9j/4AAQ...")
%ContentPart{type: :image_url, content: "data:image/jpeg;base64,/9j/4AAQ..."}

merge(part1, part2)

@spec merge(t(), t()) :: t() | {:error, :incompatible_types}

Merge content parts of the same type.

Useful for streaming where deltas arrive incrementally.

Examples

iex> part1 = ContentPart.text("Hello")
iex> part2 = ContentPart.text(" world")
iex> ContentPart.merge(part1, part2)
%ContentPart{type: :text, content: "Hello world"}

new(attrs)

@spec new(map()) :: {:ok, t()} | {:error, Ecto.Changeset.t()}

Create a new content part.

Returns {:ok, content_part} on success or {:error, changeset} on validation failure.

Examples

iex> ContentPart.new(%{type: :text, content: "Hello"})
{:ok, %ContentPart{type: :text, content: "Hello"}}

iex> ContentPart.new(%{type: :invalid})
{:error, %Ecto.Changeset{}}

new!(attrs)

@spec new!(map()) :: t()

Create a new content part, raising on validation failure.

Examples

iex> ContentPart.new!(%{type: :text, content: "Hello"})
%ContentPart{type: :text, content: "Hello"}

test_image()

@spec test_image() :: t()

Create a 1x1 pixel test image as base64 data URL.

Useful for testing multi-modal functionality.

Examples

iex> test_image = ContentPart.test_image()
iex> test_image.type
:image_url
iex> String.starts_with?(test_image.content, "data:image/png;base64,")
true

text(content)

@spec text(String.t()) :: t()

Create a text content part.

Examples

iex> ContentPart.text("Hello, world!")
%ContentPart{type: :text, content: "Hello, world!"}

thinking(content)

@spec thinking(String.t()) :: t()

Create a thinking content part for models that support reasoning.

Examples

iex> ContentPart.thinking("Let me think about this step by step...")
%ContentPart{type: :thinking, content: "Let me think about this step by step..."}

to_data_url(binary_data, mime_type)

@spec to_data_url(binary(), String.t()) :: String.t()

Convert binary image data to a data URL.

Examples

iex> binary_data = <<137, 80, 78, 71, 13, 10, 26, 10>>
iex> ContentPart.to_data_url(binary_data, "image/png")
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJ"

to_text(parts)

@spec to_text([t()]) :: String.t()

Convert content parts to plain text representation.

Examples

iex> parts = [
...>   ContentPart.text("Look at this: "),
...>   ContentPart.image_url("https://example.com/img.jpg"),
...>   ContentPart.text(" Amazing!")
...> ]
iex> ContentPart.to_text(parts)
"Look at this: [Image: https://example.com/img.jpg] Amazing!"