Skip to content

mostlyright.finance.transcripts.streaming_transcriber

Streaming STT engine.

StreamingTranscriber turns the live PCM frame stream (Iterator[tuple[pcm_bytes, spoken_at]] from mostlyright.finance.transcripts.capture.base.CaptureAdapter.live()) into incremental transcript Segments + provisional final-only :class:FactDeltas that the SSE endpoint fans out over the :class:~mostlyright.finance.transcripts.segment_bus.SegmentBus.

Pipeline:

  1. VAD-guided chunking. _vad_chunks() groups the incoming frames into ~3-5 s windows with ~0.5 s overlap. A speech run ends on a VAD speech-end (a silence gap). A lightweight energy gate (RMS over the s16le samples) sits behind a pluggable vad interface, allowing callers to provide another VAD implementation without changing this engine.
  2. Transcribe. Each in-flight window is transcribed with the per-call initial_prompt, seeded from the market strike terms via seed_initial_prompt(). faster-whisper is the engine, injected as a callable transcriber so unit tests can stub it and need neither a real WhisperModel nor real audio. The default production transcriber lazy-imports faster-whisper from the [earnings] extra.
  3. partial → final. An in-flight window emits a revisable partial Segment (is_final=False). At the speech-end boundary the segment is re-emitted as final (is_final=True) with the stabilised text.
  4. final-only counting. classify_mentions() runs over final segments only, producing FactDelta records aggregated per (term, compound_type) with resolution_status="provisional", is_final=True, and kalshi_counted=validate_kalshi_counted_occurrence(...). A term in a partial is never counted, because a retracted word must not settle a market. classify_mentions, not count_mentions, is the production counter: it also reports closed-compound candidates (firefighter for fire) that count_mentions never matches, without which a Polymarket closed-compound straddle resolves resolved_no with no review.

Authority. is_final denotes STT-segment finality only; a counted fact delta is is_final=True yet still resolution_status="provisional". Settlement and research authority are gated on resolution_status and source, never on is_final. Live deltas are early-signal rows; the post-call ledger stays authoritative.

Audio handling. Captured audio is a transient ingest artifact. The emitted Segment and FactDelta carry text and facts only, never PCM bytes, and the bus enforces the same rule structurally.

The engine supports injected transcribers and VAD implementations. Its default energy VAD is intentionally lightweight; production callers that need a more sophisticated detector can supply one through the same interface.

AttributeDescription
TranscribeFn(window_pcm, *, initial_prompt) -> text.
TurnProviderA turn provider maps a (partial) segment to the role-parser Turn whose speaker_role / role_source drive the fail-closed Kalshi rule.
ClassDescription
FactDelta(term_canonical, …[, …])A provisional live fact delta counted off a final segment, never a partial.
Segment(text, is_final, spoken_at, …[, …])One streaming transcript segment: text only, never audio.
StreamingTranscriber(*[, transcriber, …])VAD-chunked streaming STT → partial/final segments + final-only fact deltas.

class mostlyright.finance.transcripts.streaming_transcriber.FactDelta(term_canonical, matched_surface_form, mention_count, speaker_role, role_source, speaker_name, kalshi_counted, is_final, spoken_at, stream_seq, compound_type=‘standalone’, resolution_status=‘provisional’, source=‘earnings_call’)

Section titled “class mostlyright.finance.transcripts.streaming_transcriber.FactDelta(term_canonical, matched_surface_form, mention_count, speaker_role, role_source, speaker_name, kalshi_counted, is_final, spoken_at, stream_seq, compound_type=‘standalone’, resolution_status=‘provisional’, source=‘earnings_call’)”

Bases: object

A provisional live fact delta counted off a final segment, never a partial.

Shaped for schema.finance.fact.v1: resolution_status="provisional" marks it an early live signal rather than a settlement source, is_final=True is STT finality and is orthogonal to authority, and kalshi_counted is derived through the fail-closed validate_kalshi_counted_occurrence(). Text and facts only, no audio.

compound_type is per delta: one delta per (term, compound_type), never an aggregate mixing types, so the venue filters in fact_builder apply row-wise (closed candidates go to Polymarket human review; Kalshi resolves No on closed). It defaults to "standalone", so an existing SSE consumer or a persisted delta written before the field existed counts for both venues exactly as it did before.

  • Parameters:
    • term_canonical (str)
    • matched_surface_form (str)
    • mention_count (int)
    • speaker_role (str)
    • role_source (str)
    • speaker_name (str | None)
    • kalshi_counted (bool)
    • is_final (bool)
    • spoken_at (float)
    • stream_seq (int)
    • compound_type (str)
    • resolution_status (str)
    • source (str)

Map this delta to a build_fact_rows stt_counts occurrence record.

compound_type survives from the live classifier through the occurrence record into the fact row, so the venue filters and the fail-loud closed-candidate resolution operate on the same value end to end. turn_index, when known, links the occurrence to the role-parser turns list so build_fact_rows re-derives the speaker scope from the authoritative turn.

Temporal mapping: this delta’s spoken_at is an engine-relative float (seconds into the stream, for example 12.5), not a wallclock. It maps into offset_seconds, the schema’s engine-relative integer audit field that build_fact_rows already accepts. It is never emitted as the occurrence’s spoken_at: that schema column is timestamp_utc and pyarrow silently coerces a float to microseconds-after-epoch, persisting 1970-01-01 00:00:00.000012+00:00 as the temporal audit marker. spoken_at is left absent, since the column is nullable; a caller holding a genuine tz-aware wallclock sets it on the occurrence record explicitly, and build_fact_rows fails loud on any value that is not a tz-aware datetime.

class mostlyright.finance.transcripts.streaming_transcriber.Segment(text, is_final, spoken_at, stream_seq, knowledge_time, fact_deltas=)

Section titled “class mostlyright.finance.transcripts.streaming_transcriber.Segment(text, is_final, spoken_at, stream_seq, knowledge_time, fact_deltas=)”

Bases: object

One streaming transcript segment: text only, never audio.

is_final is STT-segment finality only (partial versus final text) and never gates settlement authority. spoken_at is the aired event-time wallclock of the window’s start; knowledge_time is the STT-finalization / publish wallclock (>= spoken_at). fact_deltas is populated on final segments only.

class mostlyright.finance.transcripts.streaming_transcriber.StreamingTranscriber(, transcriber=None, initial_prompt_terms=None, market_terms=None, turn_provider=None, model_size=‘small’)

Section titled “class mostlyright.finance.transcripts.streaming_transcriber.StreamingTranscriber(, transcriber=None, initial_prompt_terms=None, market_terms=None, turn_provider=None, model_size=‘small’)”

Bases: object

VAD-chunked streaming STT → partial/final segments + final-only fact deltas.

  • Parameters:
    • transcriber (Callable[..., str] | None) – A callable (window_pcm, *, initial_prompt) -> text. Pass a streaming audio transcriber explicitly. Omitting it creates a placeholder that raises NotImplementedError when transcription begins.
    • initial_prompt_terms (Sequence[str] | None) – The market strike terms the per-call initial_prompt is seeded from (reuses seed_initial_prompt()).
    • market_terms (Sequence[Mapping[str, object]] | None) – Per-term market specs (term_canonical at minimum) the final-only counter runs over. When empty, no fact deltas are produced.
    • turn_provider (Callable[[Segment], Turn | None] | None) – Maps a segment to the role-parser Turn (speaker_role / role_source) driving the fail-closed Kalshi rule. Defaults to an unknown / diarization_advisory turn (Kalshi-excluded — fail-closed).
    • model_size (str)

All fact deltas emitted this run (final-only) — inspectable by callers.

Consume (pcm_frame, spoken_at) frames → yield partial/final Segments.

For each VAD speech run: yields one revisable partial per accumulated window (is_final=False), then one final (is_final=True) on the speech-end boundary — or, for a run still open when the frames run out, at end of stream (a trailing silence frame is a caller convenience, never a precondition for a run being finalised and counted). The final segment carries the stabilised text of the entire run — every window’s transcription, with the overlap de-duplicated — not just the post-flush tail, so a term spoken early in a continuous run is counted exactly once. Fact deltas are computed on the final segment only and appended to fact_deltas (and to the final segment’s fact_deltas list).

mostlyright.finance.transcripts.streaming_transcriber.TranscribeFn

Section titled “mostlyright.finance.transcripts.streaming_transcriber.TranscribeFn”

(window_pcm, *, initial_prompt) -> text. Injected so unit tests stub it; the production default lazy-imports faster-whisper.

  • Type: A transcriber callable

alias of Callable[[…], str]

mostlyright.finance.transcripts.streaming_transcriber.TurnProvider

Section titled “mostlyright.finance.transcripts.streaming_transcriber.TurnProvider”

A turn provider maps a (partial) segment to the role-parser Turn whose speaker_role / role_source drive the fail-closed Kalshi rule. Live role attribution supplies this; tests inject a fixed turn.

alias of Callable[[Segment], Turn | None]