# `ALLM.ImageUsage`
[🔗](https://github.com/cykod/ALLM/blob/v0.5.0/lib/allm/image_usage.ex#L1)

Image-side usage and cost summary — Layer A serializable data.

`:images` defaults to `0` so a freshly-constructed `%ImageUsage{}` reads
as "no work done yet"; the `%ALLM.ImageResponse{}` struct's default
`:usage` carries one of these rather than `nil`.

## Cost types

Cost fields are typed `float | nil`. `ALLM.Usage.cost` is already
`float`, so the chat and image cost types align; adopting `Decimal`
solely for typed nil-or-number adds runtime weight without semantic
gain. Float-summation drift on `total_cost = input_cost + output_cost`
is bounded at ≤1 ULP, well below provider cent-level pricing precision.

Providers that charge by image-count alone (dall-e-2, dall-e-3) populate
`:images`, `:size`, `:quality`, and `:total_cost`. Providers that charge by
tokens (gpt-image-1) additionally populate `:input_tokens` / `:output_tokens`
/ `:input_cost` / `:output_cost`.

# `t`

```elixir
@type t() :: %ALLM.ImageUsage{
  images: non_neg_integer(),
  input_cost: float() | nil,
  input_tokens: non_neg_integer() | nil,
  output_cost: float() | nil,
  output_tokens: non_neg_integer() | nil,
  quality: String.t() | nil,
  size: String.t() | nil,
  total_cost: float() | nil
}
```

# `new`

```elixir
@spec new(keyword()) :: t()
```

Build an `%ImageUsage{}` from keyword opts.

Unknown keys raise `KeyError` via `struct!/2`.

## Examples

    iex> u = ALLM.ImageUsage.new(images: 1, input_tokens: 100)
    iex> u.images
    1
    iex> u.input_tokens
    100
    iex> u.size
    nil

---

*Consult [api-reference.md](api-reference.md) for complete listing*
