Skip to main content

lib/jido/chat/content/audio.ex

defmodule Jido.Chat.Content.Audio do
  @moduledoc """
  Audio content block for messages.

  Represents an audio attachment (voice messages, audio files).

  ## Fields

  - `url` - URL to the audio file (optional if data is provided)
  - `data` - Base64-encoded audio data (optional if url is provided)
  - `media_type` - MIME type (e.g., "audio/mp3", "audio/ogg")
  - `duration` - Duration in seconds (optional)
  - `transcript` - Text transcript of the audio (optional)

  ## Examples

      Audio.new("https://example.com/voice.ogg")
      Audio.new("https://example.com/voice.ogg", media_type: "audio/ogg", duration: 15)
  """

  @schema Zoi.struct(
            __MODULE__,
            %{
              type: Zoi.literal(:audio) |> Zoi.default(:audio),
              url: Zoi.string() |> Zoi.nullish(),
              data: Zoi.string() |> Zoi.nullish(),
              media_type: Zoi.string() |> Zoi.nullish(),
              duration: Zoi.integer() |> Zoi.nullish(),
              transcript: Zoi.string() |> Zoi.nullish()
            },
            coerce: true
          )

  @type t :: unquote(Zoi.type_spec(@schema))

  @enforce_keys Zoi.Struct.enforce_keys(@schema)
  defstruct Zoi.Struct.struct_fields(@schema)

  @doc "Returns the Zoi schema for Audio content"
  def schema, do: @schema

  @doc """
  Creates a new audio content block from a URL.

  ## Options

  - `:media_type` - MIME type of the audio
  - `:duration` - Duration in seconds
  - `:transcript` - Text transcript
  """
  def new(url, opts \\ []) when is_binary(url) do
    %__MODULE__{
      url: url,
      media_type: Keyword.get(opts, :media_type),
      duration: Keyword.get(opts, :duration),
      transcript: Keyword.get(opts, :transcript)
    }
  end

  @doc """
  Creates a new audio content block from base64-encoded data.
  """
  def from_base64(data, media_type, opts \\ []) when is_binary(data) and is_binary(media_type) do
    %__MODULE__{
      data: data,
      media_type: media_type,
      duration: Keyword.get(opts, :duration),
      transcript: Keyword.get(opts, :transcript)
    }
  end
end