# `ALLM.TranscriptionResponse`
[🔗](https://github.com/cykod/ALLM/blob/v0.6.1/lib/allm/transcription_response.ex#L1)

A speech-to-text response. Layer A serializable data.

    iex> resp = ALLM.TranscriptionResponse.new(text: "The quick brown fox.")
    iex> resp.text
    "The quick brown fox."

## Fields

- `:text`: the transcript, as plain text.
- `:spans`: the transcript's words or tokens as `t:ALLM.TranscriptSpan.t/0`
  values, in order, carrying start and end times when the request set
  `timestamps: true` and log-probabilities when it set `logprobs: true`.
  `nil` means neither flag was set; `[]` means a flag was set and nothing
  was spoken. Segment-level timestamps, speaker labels and subtitle
  formats are not modelled, and the provider's full body stays on `:raw`
  for callers who need them. `mean_logprob/1` summarizes the spans.
- `:language`: the spoken language as the provider reports it, not
  normalized, or `nil`.
- `:duration_seconds`: billed audio seconds, when the provider bills
  transcription by duration.
- `:id`, `:request_id`, `:model`, `:provider`: provider correlation.
- `:usage`: an `t:ALLM.Usage.t/0`, never `nil`. Providers that bill in
  tokens populate it, and a response carrying no counters holds
  `%ALLM.Usage{}` with every field `nil`. Billed seconds go in
  `:duration_seconds` rather than `Usage.extra`, because a typed field
  survives a JSON round-trip without its keys turning from atoms into
  strings.
- `:raw`: the provider's response body.
- `:metadata`: caller-owned.

A transcript produced by a general-purpose model prompted to transcribe,
rather than by a dedicated speech model, is not guaranteed to be
verbatim.

# `t`

```elixir
@type t() :: %ALLM.TranscriptionResponse{
  duration_seconds: number() | nil,
  id: String.t() | nil,
  language: String.t() | nil,
  metadata: map(),
  model: String.t() | nil,
  provider: atom() | nil,
  raw: term(),
  request_id: String.t() | nil,
  spans: [ALLM.TranscriptSpan.t()] | nil,
  text: String.t(),
  usage: ALLM.Usage.t()
}
```

# `mean_logprob`

```elixir
@spec mean_logprob(t()) :: float() | nil
```

The mean log-probability of the response's spoken units, or `nil`.

Averages `:logprob` over the spans whose `:kind` is `:word` or `:token`
and whose `:logprob` is a number. `:spacing` and `:audio_event` spans are
left out because they are not spoken units, and some providers copy the
next word's log-probability onto the spacing before it, which would
count that word twice. Returns `nil` when `:spans` is `nil` or no span
qualifies.

## Examples

    iex> spans = [
    ...>   ALLM.TranscriptSpan.new(text: "quick", kind: :word, logprob: -0.25),
    ...>   ALLM.TranscriptSpan.new(text: " ", kind: :spacing, logprob: -0.25),
    ...>   ALLM.TranscriptSpan.new(text: "fox", kind: :word, logprob: -0.5)
    ...> ]
    iex> ALLM.TranscriptionResponse.mean_logprob(ALLM.TranscriptionResponse.new(spans: spans))
    -0.375

    iex> ALLM.TranscriptionResponse.mean_logprob(ALLM.TranscriptionResponse.new())
    nil

# `new`

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

Build a `%TranscriptionResponse{}` from keyword opts.

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

## Examples

    iex> resp = ALLM.TranscriptionResponse.new()
    iex> {resp.text, resp.usage}
    {"", %ALLM.Usage{}}

---

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