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:
- 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 pluggablevadinterface, allowing callers to provide another VAD implementation without changing this engine. - Transcribe. Each in-flight window is transcribed with the per-call
initial_prompt, seeded from the market strike terms viaseed_initial_prompt(). faster-whisper is the engine, injected as a callabletranscriberso unit tests can stub it and need neither a realWhisperModelnor real audio. The default production transcriber lazy-imports faster-whisper from the[earnings]extra. - 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. - final-only counting.
classify_mentions()runs over final segments only, producingFactDeltarecords aggregated per(term, compound_type)withresolution_status="provisional",is_final=True, andkalshi_counted=validate_kalshi_counted_occurrence(...). A term in a partial is never counted, because a retracted word must not settle a market.classify_mentions, notcount_mentions, is the production counter: it also reports closed-compound candidates (firefighterforfire) thatcount_mentionsnever matches, without which a Polymarket closed-compound straddle resolvesresolved_nowith 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.
Module Attributes
Section titled “Module Attributes”| Attribute | Description |
|---|---|
TranscribeFn | (window_pcm, *, initial_prompt) -> text. |
TurnProvider | A turn provider maps a (partial) segment to the role-parser Turn whose speaker_role / role_source drive the fail-closed Kalshi rule. |
Classes
Section titled “Classes”| Class | Description |
|---|---|
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:
compound_type: str
Section titled “compound_type: str”is_final: bool
Section titled “is_final: bool”kalshi_counted: bool
Section titled “kalshi_counted: bool”matched_surface_form: str
Section titled “matched_surface_form: str”mention_count: int
Section titled “mention_count: int”resolution_status: str
Section titled “resolution_status: str”role_source: str
Section titled “role_source: str”source: str
Section titled “source: str”speaker_name: str | None
Section titled “speaker_name: str | None”speaker_role: str
Section titled “speaker_role: str”spoken_at: float
Section titled “spoken_at: float”stream_seq: int
Section titled “stream_seq: int”term_canonical: str
Section titled “term_canonical: str”to_stt_count(, turn_index=None)
Section titled “to_stt_count(, turn_index=None)”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.
- Parameters:
fact_deltas: list[FactDelta]
Section titled “fact_deltas: list[FactDelta]”is_final: bool
Section titled “is_final: bool”knowledge_time: float
Section titled “knowledge_time: float”spoken_at: float
Section titled “spoken_at: float”stream_seq: int
Section titled “stream_seq: int”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 raisesNotImplementedErrorwhen transcription begins. - initial_prompt_terms (
Sequence[str] |None) – The market strike terms the per-callinitial_promptis seeded from (reusesseed_initial_prompt()). - market_terms (
Sequence[Mapping[str,object]] |None) – Per-term market specs (term_canonicalat 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-parserTurn(speaker_role / role_source) driving the fail-closed Kalshi rule. Defaults to anunknown/diarization_advisoryturn (Kalshi-excluded — fail-closed). - model_size (str)
- transcriber (
fact_deltas: list[FactDelta]
Section titled “fact_deltas: list[FactDelta]”All fact deltas emitted this run (final-only) — inspectable by callers.
run(frame_iter)
Section titled “run(frame_iter)”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
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]