A serializable audio value, used as transcription input and as speech synthesis output. Layer A serializable data.
One value type serves both directions. ALLM.TranscriptionRequest carries
an %Audio{} in :audio, and ALLM.SpeechResponse returns the synthesized
bytes as %Audio{source: {:binary, bytes}}.
iex> audio = ALLM.Audio.from_binary(<<1, 2, 3>>, "audio/wav")
iex> ALLM.Audio.size(audio)
{:ok, 3}Source variants
{:binary, bytes}: raw audio bytes plus an explicit:mime_type, viafrom_binary/2.{:base64, encoded}: standard base64-encoded bytes plus an explicit:mime_type, viafrom_base64/2. The string is stored as given and is not checked untilto_binary/1orsize/1decodes it.{:file, path}: a local filesystem path, viafrom_file/1. Building one does no I/O. The file is read only byto_binary/1, andsize/1only stats it.
There is no URL variant: no bundled provider accepts a URL for audio input.
MIME types
from_file/1 infers :mime_type from the lowercased extension:
.mp3, .mpeg, .mpga → audio/mpeg; .mp4, .m4a → audio/mp4;
.wav → audio/wav; .webm → audio/webm; .ogg, .oga →
audio/ogg; .flac → audio/flac; .aac → audio/aac; .opus →
audio/opus; .aiff → audio/aiff. Any other extension leaves it nil,
and the adapter decides what to do with an unknown type.
Construction
Build values with the from_* functions. There is no new/1. :source is
enforced, so struct!(ALLM.Audio, []) raises ArgumentError.
Inspection
inspect/1 prints a payload as its size, never its bytes, so a
multi-megabyte clip in an error message, a test failure diff, a log line
or a telemetry handler costs one short line:
iex> inspect(ALLM.Audio.from_binary(<<0, 0, 0, 0>>, "audio/wav"))
~s(#ALLM.Audio<source: {:binary, <<4 bytes>>}, mime_type: "audio/wav", metadata: %{}>)Serializability
ETF round-trip preserves every source variant verbatim. JSON round-trip
through ALLM.Serializer writes :source as
%{"type" => "<kind>", "value" => <value>}, and the {:binary, _} variant
base64-encodes its bytes so that non-UTF-8 audio survives as JSON text.
A "binary" source whose value is not valid base64 decodes to the field
error {[:source], :invalid_base64}. An unknown source type decodes to
{:_unknown, :atom_decode_failed}.
:metadata is caller-owned. Use string keys when it will round-trip
through JSON: atom keys come back as strings.
Summary
Functions
Build an %Audio{} from a base64-encoded string plus an explicit MIME type.
Build an %Audio{} from raw bytes plus an explicit MIME type.
Build an %Audio{} from a local filesystem path.
The audio payload's size in bytes, without reading a file.
Resolve the audio's :source to raw bytes.
Types
Functions
Build an %Audio{} from a base64-encoded string plus an explicit MIME type.
The string is not decoded here. Invalid base64 surfaces later, as
{:error, :invalid_base64} from to_binary/1 or size/1.
Examples
iex> audio = ALLM.Audio.from_base64("aGk=", "audio/mpeg")
iex> audio.source
{:base64, "aGk="}
Build an %Audio{} from raw bytes plus an explicit MIME type.
Examples
iex> audio = ALLM.Audio.from_binary(<<0, 255>>, "audio/wav")
iex> audio.source
{:binary, <<0, 255>>}
iex> audio.mime_type
"audio/wav"
Build an %Audio{} from a local filesystem path.
Does no I/O: the path is stored as given, so a path that does not exist
yet builds fine. :mime_type is inferred from the lowercased extension,
or nil when the extension is missing or not in the table.
Examples
iex> audio = ALLM.Audio.from_file("/tmp/clip.MP3")
iex> audio.source
{:file, "/tmp/clip.MP3"}
iex> audio.mime_type
"audio/mpeg"
iex> ALLM.Audio.from_file("/tmp/clip.xyz").mime_type
nil
@spec size(t()) :: {:ok, non_neg_integer()} | {:error, :invalid_base64 | :invalid_source | File.posix()}
The audio payload's size in bytes, without reading a file.
{:binary, b}measures the bytes.{:base64, s}decodes and measures, or returns{:error, :invalid_base64}.{:file, path}stats the file and never reads it; a missing file returns{:error, :enoent}, and a directory returns{:error, :eisdir}, the same errorto_binary/1gives for it.- Any other
:sourceshape returns{:error, :invalid_source}.
Examples
iex> ALLM.Audio.size(ALLM.Audio.from_binary(<<1, 2, 3>>, "audio/wav"))
{:ok, 3}
iex> ALLM.Audio.size(ALLM.Audio.from_base64("%%%", "audio/wav"))
{:error, :invalid_base64}
@spec to_binary(t()) :: {:ok, binary()} | {:error, :invalid_base64 | :invalid_source | File.posix()}
Resolve the audio's :source to raw bytes.
{:binary, b}returns{:ok, b}.{:base64, s}decodes, or returns{:error, :invalid_base64}.{:file, path}reads the file, returningFile.read/1's error on failure ({:error, :enoent}for a missing file).- Any other
:sourceshape (only reachable by building the struct by hand) returns{:error, :invalid_source}.
Examples
iex> ALLM.Audio.to_binary(ALLM.Audio.from_base64("aGk=", "audio/wav"))
{:ok, "hi"}
iex> ALLM.Audio.to_binary(ALLM.Audio.from_file("/definitely/not/here.mp3"))
{:error, :enoent}