ALLM.TranscriptionEvent (allm v0.6.1)

Copy Markdown View Source

Closed tagged-tuple union emitted by a streaming transcription call. Layer A data.

Every event is {tag, payload}, one of:

  • {:transcription_started, started}: the session opened. The payload carries :request_id, :model, :provider and the provider's :session_id, each possibly nil.
  • {:partial_transcript, %{text: text}}: the current best guess for the segment being spoken. It replaces the previous partial of the same segment; it is not appended.
  • {:committed_transcript, %{text: text, language: language}}: a final segment. Committed segments are appended. When the request set timestamps: true or logprobs: true, the payload also carries a :spans key: the segment's ALLM.TranscriptSpan.t/0 list, or nil when the adapter has no trustworthy span data for that segment. With both flags off the key is absent, not nil.
  • {:transcription_completed, completed}: the stream finished. The payload carries :text, :language, :duration_seconds, :request_id, :usage (an ALLM.Usage.t/0) and :metadata. When a flag was set it also carries an optional :spans key: the committed segments' spans concatenated in order, [] when none were committed.
  • {:error, %ALLM.Error.TranscriptionAdapterError{}}: the stream failed.

Stream grammar

A successful stream is one :transcription_started, then any number of segments (zero or more :partial_transcript events followed by one :committed_transcript), then zero or more trailing :partial_transcript events, then one :transcription_completed. A failed stream ends with one :error. Nothing follows a terminal event.

The completed payload

:text is the whole transcript: each committed segment's text is trimmed, empty segments are dropped, and the rest are joined with one space. The adapter computes it, so a consumer does not need to fold the segments itself.

:spans, when present, is likewise the adapter's concatenation of the committed segments' spans. It is optional, so transcription_completed/1 does not require it.

:duration_seconds is computed, not reported by the provider: the audio bytes sent divided by sample_rate * 2 (16-bit mono PCM).

Serializability

Events round-trip through :erlang.term_to_binary/1. They are not JSON-encoded, matching ALLM.SpeechEvent.

Closed union

Adding a variant is a breaking change for any reducer of this union, the same rule as ALLM.Event. Adding a key to an existing payload map is not. event?/1 is false on every chat event. The reverse does not hold: ALLM.Event.event?/1 treats :error payloads as opaque, so it also returns true on this union's :error event. Route by this module's event?/1, or by the error struct.

Build events with the variant constructors, which check the payload's required keys. :error has no constructor; its payload is the error struct.

Summary

Types

Payload of :committed_transcript. :spans is present only when a span flag was set.

Payload of :transcription_completed. :spans is present only when a span flag was set.

Payload of :transcription_started.

t()

Functions

Build a :committed_transcript event.

Build a :committed_transcript event carrying the segment's spans.

Return true when value is a well-shaped ALLM.TranscriptionEvent.

Build a :partial_transcript event.

Build a :transcription_completed event.

Build a :transcription_started event.

Types

committed()

@type committed() :: %{
  :text => String.t(),
  :language => String.t() | nil,
  optional(:spans) => [ALLM.TranscriptSpan.t()] | nil
}

Payload of :committed_transcript. :spans is present only when a span flag was set.

completed()

@type completed() :: %{
  :text => String.t(),
  :language => String.t() | nil,
  :duration_seconds => number() | nil,
  :request_id => String.t() | nil,
  :usage => ALLM.Usage.t(),
  :metadata => map(),
  optional(:spans) => [ALLM.TranscriptSpan.t()]
}

Payload of :transcription_completed. :spans is present only when a span flag was set.

started()

@type started() :: %{
  request_id: String.t() | nil,
  model: String.t() | nil,
  provider: atom() | nil,
  session_id: String.t() | nil
}

Payload of :transcription_started.

t()

@type t() ::
  {:transcription_started, started()}
  | {:partial_transcript, %{text: String.t()}}
  | {:committed_transcript, committed()}
  | {:transcription_completed, completed()}
  | {:error, ALLM.Error.TranscriptionAdapterError.t()}

Functions

committed_transcript(text, language \\ nil)

@spec committed_transcript(String.t(), String.t() | nil) :: t()

Build a :committed_transcript event.

The payload has exactly :text and :language, and no :spans key. committed_transcript/3 is the form that carries spans.

Examples

iex> ALLM.TranscriptionEvent.committed_transcript("hello", "en")
{:committed_transcript, %{text: "hello", language: "en"}}

committed_transcript(text, language, spans)

@spec committed_transcript(
  String.t(),
  String.t() | nil,
  [ALLM.TranscriptSpan.t()] | nil
) :: t()

Build a :committed_transcript event carrying the segment's spans.

Always writes the :spans key, even when it is nil (the adapter has no trustworthy span data for this segment). An adapter uses this form for every committed segment when the request set timestamps: true or logprobs: true, and committed_transcript/2 otherwise. Raises FunctionClauseError when spans is neither a list nor nil.

Examples

iex> span = ALLM.TranscriptSpan.new(text: "hello", kind: :word, start_seconds: 0.0, end_seconds: 0.4)
iex> {:committed_transcript, payload} = ALLM.TranscriptionEvent.committed_transcript("hello", "en", [span])
iex> payload.spans == [span]
true

event?(arg1)

@spec event?(term()) :: boolean()

Return true when value is a well-shaped ALLM.TranscriptionEvent.

The tag must be one of the five variants. :partial_transcript and :committed_transcript need a map payload with a binary :text, the other structured variants a map, and :error an %ALLM.Error.TranscriptionAdapterError{}.

Examples

iex> ALLM.TranscriptionEvent.event?({:partial_transcript, %{text: "hi"}})
true

iex> ALLM.TranscriptionEvent.event?({:text_delta, %{id: nil, delta: "hi"}})
false

partial_transcript(text)

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

Build a :partial_transcript event.

Examples

iex> ALLM.TranscriptionEvent.partial_transcript("hel")
{:partial_transcript, %{text: "hel"}}

transcription_completed(payload)

@spec transcription_completed(completed()) :: t()

Build a :transcription_completed event.

Raises ArgumentError when payload lacks any of :text, :language, :duration_seconds, :request_id, :usage or :metadata. :spans is optional and passes through when present.

Examples

iex> {:transcription_completed, p} =
...>   ALLM.TranscriptionEvent.transcription_completed(%{
...>     text: "hello world", language: nil, duration_seconds: 1.5,
...>     request_id: nil, usage: %ALLM.Usage{}, metadata: %{}
...>   })
iex> p.text
"hello world"

transcription_started(payload)

@spec transcription_started(started()) :: t()

Build a :transcription_started event.

Raises ArgumentError when payload lacks any of :request_id, :model, :provider or :session_id (a key may be present with a nil value).

Examples

iex> ALLM.TranscriptionEvent.transcription_started(%{request_id: nil, model: "m", provider: :fake, session_id: nil})
{:transcription_started, %{request_id: nil, model: "m", provider: :fake, session_id: nil}}