Skip to content

mostlyright.weather.earnings.streaming_transcriber

mostlyright.weather.earnings.streaming_transcriber

Section titled “mostlyright.weather.earnings.streaming_transcriber”

Streaming STT engine (Phase 27, 27-10 Task 2).

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

Pipeline (per D-27.14 / D-27.16, RESEARCH-LIVE-STREAMING §2):

  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). The plan mandates NO torch / NO silero here — we use a LIGHTWEIGHT energy gate (RMS over the s16le samples) behind a pluggable vad interface, so a real Silero-ONNX VAD can be dropped in later WITHOUT touching this engine (and without tripping the 27-03 package-legitimacy gate for a new pip dep).
  2. Transcribe. Each in-flight window is transcribed with the per-call initial_prompt (seeded from the market strike terms via the 27-03 seed_initial_prompt()). faster-whisper is the D-27.5 engine — it is injected as a callable transcriber so unit tests stub it and NO real WhisperModel / no real audio is needed. The default production transcriber lazy-imports faster-whisper (behind the [earnings] extra).
  3. partial → final. An in-flight window emits a revisable PARTIAL Segment (is_final=False). On the speech-end boundary the segment is re-emitted FINAL (is_final=True) with the stabilised text.
  4. final-only counting. classify_mentions() runs over FINAL segments ONLY → FactDeltas aggregated per (term, compound_type) (resolution_status="provisional", is_final=True, kalshi_counted=validate_kalshi_counted_occurrence(...)). A term in a PARTIAL is NEVER counted (else a retracted word settles a market — T-27-35). classify_mentions (NOT count_mentions) is the production counter (D-30, review F1): it additionally surfaces CLOSED-compound candidates (firefighter for fire) that count_mentions never matches — without them a Polymarket closed-straddle silently resolved resolved_no.

Authority (D-27.16, codex P2). is_final denotes STT-segment finality ONLY; a counted fact delta is is_final=True yet STILL resolution_status="provisional". Settlement/backtest authority is gated on resolution_status / source, NEVER on is_final. Live deltas are early-signal rows — the post-call ledger (27-04) stays authoritative.

Legal (D-27.9). Audio is a TRANSIENT ingest artifact — the emitted Segment / FactDelta carry TEXT + facts ONLY, never PCM bytes. The bus (27-10 Task 3) enforces the same gate structurally.

DEFERRED (operator / live). This engine is fully implemented + tested against SYNTHETIC PCM and a STUB transcriber. Validation against a REAL live earnings webcast (a webcast in progress) and a real faster-whisper model on real audio requires an operator with a live call and the [earnings] extra installed — that end-to-end run is DEFERRED and cannot be exercised in unit tests. The energy VAD is a floor; swapping in a real Silero-ONNX VAD (which would add a pip dep and must clear the 27-03 package-legitimacy checkpoint) is also deferred.

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.
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, D-27.9).
StreamingTranscriber(*[, transcriber, …])VAD-chunked streaming STT → partial/final segments + final-only fact deltas.

class mostlyright.weather.earnings.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.weather.earnings.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.earnings_fact.v1: resolution_status="provisional" (live early-signal — NOT a settlement source), is_final=True (STT finality — orthogonal to authority), kalshi_counted derived via the unchanged fail-closed validate_kalshi_counted_occurrence() (D-27.11, mode-agnostic). TEXT/facts only — no audio (D-27.9).

compound_type (D-30, review F1) is the per-delta compound axis — one delta per (term, compound_type), never an aggregate mixing types, so the venue filters in fact_builder apply row-wise (closed candidates surface for Polymarket human review; Kalshi-No on closed). ADDITIVE with default "standalone": an existing SSE consumer or a persisted pre-fix delta is unaffected (standalone counts for both venues exactly as before the axis).

  • 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.

The propagation seam (review F1): compound_type survives from the live classifier through the occurrence record into the fact row, so the venue filters + the fail-loud closed-candidate resolution operate on the SAME axis 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 (review R2-F3): this delta’s spoken_at is an ENGINE-RELATIVE float (seconds into the stream, e.g. 12.5), NOT a wallclock. It maps into offset_seconds — the schema’s engine-relative int audit field, which 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 (the column is nullable); a caller holding a genuine tz-aware wallclock sets it on the occurrence record explicitly — build_fact_rows fail-louds on any non-tz-aware-datetime value.

class mostlyright.weather.earnings.streaming_transcriber.Segment(text, is_final, spoken_at, stream_seq, knowledge_time, fact_deltas=)

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

Bases: object

One streaming transcript segment — TEXT ONLY (never audio, D-27.9).

is_final is STT-segment finality ONLY (partial vs final text, D-27.14); it 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, D-27.16). fact_deltas is populated on FINAL segments ONLY.

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

Section titled “class mostlyright.weather.earnings.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. Injected so unit tests stub faster-whisper. When None, a lazy faster-whisper transcriber is built (DEFERRED / operator-only path).
    • initial_prompt_terms (Sequence[str] | None) – The market strike terms the per-call initial_prompt is seeded from (reuses 27-03 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. The FINAL carries the STABILISED text of the ENTIRE run (every window’s transcription, 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.weather.earnings.streaming_transcriber.TranscribeFn

Section titled “mostlyright.weather.earnings.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.weather.earnings.streaming_transcriber.TurnProvider

Section titled “mostlyright.weather.earnings.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. 27-04’s live role attribution supplies this; tests inject a fixed turn.

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