Standard ASR

standard_asr.contract.results

The constant-shape transcription result and its components.

Standard ASR transcription result models (constant schema).

The result schema is constant: capabilities and parameters decide whether optional fields are populated, never the return type's shape (spec, section "Transcription Result"). The same Segment / Word submodels are shared between batch results and streaming events.

Null rules (disambiguation):

  • A field is None -> the data was not requested / not applicable.
  • A field is [] -> it was requested but is empty (for example, silence).
  • Whether a feature is supported is answered by capabilities, never by a field being None.

ChannelResult#classSource

class ChannelResult(BaseModel)

Per-channel transcription for multi-channel audio.

Raises
  • ValueError

    If field validation fails.

Attributes
NameTypeDescription
channelint
ge=0

Channel index.

textstr

Full transcript for this channel.

segments
= None
list[Segment] | None

Optional segment-level details for this channel.

words
= None
list[Word] | None

Optional flattened word-level details for this channel.

DIAG_SEGMENT_TIMESTAMPS_UNAVAILABLE#attributeSource

DIAG_SEGMENT_TIMESTAMPS_UNAVAILABLE = 'segment_timestamps_unavailable'

Diagnostic#classSource

class Diagnostic(BaseModel)

A structured, non-fatal notification from the standard layer.

Diagnostics report lossy conversions, assumed parameters, best_effort degradations, and similar non-ideal paths.

Attributes
NameTypeDescription
level
= 'info'
Literal['info', 'warning']

Severity, "info" or "warning".

codestr

Stable machine-readable code (for example, "audio_conversion").

messagestr

Human-readable explanation.

param
= None
str | None

The parameter the diagnostic concerns, if any.

provided
= None
WireJsonValue

The value the application provided, if relevant.

effective
= None
WireJsonValue

The value that took effect, if relevant.

Segment#classSource

class Segment(BaseModel)

Segment-level detail, shared between batch results and streaming events.

Note

start / end follow the same time frame as Word: non-negative finite float seconds with origin at the first submitted sample (t=0), end >= start (zero-duration allowed), and NaN / Inf rejected -- OR None when the engine measured no such time. None is data, not absence-of-field: the values themselves are the single source of timing truth (there is no side-channel marker), and the legal shapes are pinned by timestamp_status. An end without a start is unrepresentable (rejected at construction): no engine measures where speech stopped without knowing it started.

Ordering: within one channel, MEASURED segments are time-ordered, and the top-level TranscriptionResult.segments with a start are sorted by (start, channel, speaker) (cross-channel spans may overlap; speaker is the final tie-break for equal-(start, channel) overlapping segments, None sorting before any real label). A start=None segment has no time position: the producer keeps the list in READING order instead (list order is the reading order, and TranscriptionResult.text joins segment texts in list order), so a single unmeasured segment never scrambles -- or forces fabricated positions into -- an otherwise real timeline.

Raises
  • ValueError

    If field validation fails (incl. NaN/Inf, a negative time, end < start, or end without start).

Attributes
NameTypeDescription
startfloat | None
ge=0.0

Segment start time in seconds (origin = first submitted sample; non-negative, finite), or None when unmeasured.

endfloat | None
ge=0.0

Segment end time in seconds (non-negative, finite, >= start), or None when unmeasured. Requires start.

textstr

Segment transcript text.

words
= None
list[Word] | None

Optional word-level details for this segment.

speaker
= None
str | None

Optional speaker label (authoritative diarization shape).

channel
= None
int | None
ge=0

Optional channel index for provenance (>= 0).

avg_logprob
= None
float | None

Optional average log-probability.

no_speech_prob
= None
float | None

Optional no-speech probability.

temperature
= None
float | None

Optional decoding temperature.

compression_ratio
= None
float | None

Optional compression-ratio metric.

extra
= dict()
WireExtra

Engine-specific extra data (engine-owned; the standard reserves no keys here).

timestamp_statusLiteral['measured', 'start_only', 'unavailable']

The segment's timing shape, derived from start/end.

Derived, not stored: the nullable values are the single source of truth, so the status can never disagree with them (the previous design stored fabricated 0.0 spans guarded by a mutable side-channel marker -- two truths that could, and did, diverge).

TranscriptionResult#classSource

class TranscriptionResult(BaseModel)

The constant-shape result returned by transcribe and stream reduction.

The top-level text / segments / words are always the complete, channel- and speaker-agnostic transcription. For multi-channel audio they are the time-merge of all channels (never channel-0-only), so ignoring channels is always safe and lossless.

Raises
  • ValueError

    If field validation fails (incl. NaN/Inf, a negative duration, or a malformed detected_language).

Attributes
NameTypeDescription
textstr

Full transcript (required).

detected_language
= None
str | None

Detected language as a well-formed BCP-47 tag in auto mode; None when not applicable.

language_confidence
= None
float | None
ge=0.0, le=1.0

Detection confidence in [0, 1].

duration
= None
float | None
ge=0.0

Audio duration in seconds, if known (non-negative, finite).

segments
= None
list[Segment] | None

Segments across all channels, if available. Segments WITH a start SHOULD be sorted by (start, channel, speaker) (monotonic within a channel; speaker is the final tie-break, None sorting first); a start=None segment has no time position, so the list stays in READING order instead (list order is the reading order; text joins segment texts in list order). The ordering is an engine obligation, neither enforced at construction nor checked by the compliance suite (the streaming reducer keeps arrival order whenever any retained segment lacks a start). The SRT/VTT renderers' defensive re-sort of measured cues is the only standard-layer safety net.

words
= None
list[Word] | None

Flattened word-level details, if available.

channels
= None
list[ChannelResult] | None

Per-channel results when channel separation was performed. Each channel index MUST be unique (one entry per channel), enforced at construction.

diagnostics
= lambda: cast('list[Diagnostic]', [])()
list[Diagnostic]

Conversion / best_effort / degradation diagnostics.

extra
= dict()
WireExtra

Engine-specific / experimental data (incl. provider formats).

Word#classSource

class Word(BaseModel)

Word-level detail, shared between batch results and streaming events.

Note

Time is measured in float seconds with the origin at the first submitted sample (audio time t=0), the same origin as the streaming cursor. start / end are therefore non-negative finite floats and end >= start (a zero-duration span is allowed). NaN / Inf are rejected (allow_inf_nan=False). Engines convert ms / protobuf-duration / ticks into this frame; a negative or inverted span is an engine bug, so the model refuses to represent one rather than let it surface as a silent wrong timestamp downstream.

Raises
  • ValueError

    If field validation fails (incl. NaN/Inf, a negative time, or end < start).

Attributes
NameTypeDescription
startfloat
ge=0.0

Word start time in seconds (origin = first submitted sample; non-negative, finite).

endfloat
ge=0.0

Word end time in seconds (non-negative, finite, >= start).

textstr

Word text.

probability
= None
float | None
ge=0.0, le=1.0

Optional confidence in [0, 1].

logprob
= None
float | None

Optional log-probability (kept separate from probability).

speaker
= None
str | None

Optional speaker label.

channel
= None
int | None
ge=0

Optional channel index for provenance (>= 0).

extra
= dict()
WireExtra

Engine-specific extra data.

synthesize_segment_speaker#functionSource

def synthesize_segment_speaker(words: Sequence[Word] | None) -> str | None

Derive a segment-level speaker label from its words (the pinned synthesis rule).

THE single synthesis rule of the standard layer, used when an engine populates Word.speaker but leaves the authoritative Segment.speaker None:

  • Majority by word count -- the label carried by the most words wins.
  • Tie -> the speaker of the earliest (lowest-index) word among the tied labels.
  • Words with speaker=None do not vote.
  • No speaker-bearing words (or words None/empty) -> None.

This function is deliberately the ONLY implementation -- both the batch post-processing (EngineBase.transcribe) and the streaming reducer (StreamReducer) call it, never a private copy. Portability demands it: the same engine and audio MUST yield the same Segment.speaker whether the app took the batch or the streaming path; two drifting copies of the rule would silently break that promise.

Parameters
NameTypeDescription
wordsSequence[Word] | None

The segment's word-level details, or None.

Returns
  • str | None

    The synthesized speaker label, or None when no word carries one.

to_json_value#functionSource

def to_json_value(value: object) -> JsonValue

Project a Python value into the wire value space.

Every wire-visible slot -- Diagnostic.provided / effective, every extra mapping -- is declared JsonValue, because the Python objects and the JSON documents are meant to be the same protocol seen twice (G5.2). Declaring them Any admitted values with no JSON representation at all, which then failed during the wire projection -- after an endpoint had already committed to a response.

Two things stand between an ordinary value and that declaration, and this helper is where both are handled:

  • a structured value (a pydantic submodel such as a DiarizationRequest) has a JSON form but is not itself JSON, so it is dumped;
  • a typed container (list[str], dict[str, int]) IS JSON data, but a type checker does not accept it where list[JsonValue] is expected, because list is invariant. That is a static-analysis artifact, not a real mismatch, so it is absorbed here once instead of forcing a cast at every call site.

Runtime validation is unaffected: the model still validates what it is given, so a value that is genuinely not JSON is rejected loudly at construction, naming the field.

Parameters
NameTypeDescription
valueobject

The value to hand to a wire-visible slot.

Returns
  • JsonValue

    The value's JSON projection.

validate_speaker_label#functionSource

def validate_speaker_label(value: str | None) -> str | None

Validate a speaker label at construction (shared by every speaker field).

One rule for Segment, Word, and TranscriptionEvent: a label must be non-empty, not whitespace-only, and carry no leading/trailing whitespace. "" would be an undefined third state between None (no attribution) and a real label; edge whitespace ("A " vs "A") silently breaks within-result label consistency -- two strings = two speakers -- so both are rejected, never normalized (normalizing would hide an engine bug behind a silently rewritten value; the same stance as phrase_hints). None (no attribution) passes through.

Parameters
NameTypeDescription
valuestr | None

The candidate speaker label, or None.

Returns
  • str | None

    The validated value unchanged.

Raises
  • ValueError

    If value is empty, whitespace-only, or has leading or trailing whitespace.

On this page