Skip to content

mostlyright.finance.transcripts.stt

faster-whisper STT transcriber + alias-aware mention counter.

Two parts:

SttTranscriber : Wraps faster-whisper’s WhisperModel (CTranslate2). large-v3 is the default and the model the hosted path runs; small is the on-device earnings.live floor, which counts jargon correctly on clean prepared remarks at roughly 13% WER with no torch dependency. transcribe threads a per-call initial_prompt through to the model (WhisperModel.transcribe(..., initial_prompt=...)) for vocabulary biasing. Every segment record carries the engine’s decode statistics (avg_logprob, no_speech_prob, compression_ratio, temperature) and the result carries language_probability; the decode computes all of them anyway. Per-word {word, start, end, probability} records are opt-in via transcribe(..., word_timestamps=True), because alignment is a second pass and slows the decode. faster_whisper is lazy-imported inside transcribe and guarded by the [earnings] extra, so importing this module and running the unit tests, which mock WhisperModel, needs no heavy dependency.

seed_initial_prompt / count_mentions : Term seeding plus the alias-aware mention counter. seed_initial_prompt builds the per-call initial_prompt from the live market’s custom_strike target terms, exploding slash-synonyms. count_mentions counts a term’s mentions in a transcript, never by exact string equality: it explodes slash-synonyms and English plural/possessive forms — not verb tense, per the Kalshi contract terms — and matches the acronym plural and possessive (APIs, API's). Spelled-out separator matching (O-C-I / O.C.I / O C I) is not performed: it false-positived on short acronyms and longer spelled sequences (A I inside A I R), so acronym emission relies on the per-call initial_prompt biasing instead. Known ASR mis-renders (OCI rendered as OCR or OCIP) are opt-in via asr_misrenders=True, off by default so OCR, a legitimate standalone term, does not over-count. It returns (mention_count, [matched_surface_form, ...]): the integer is the primary tally, from which the boolean is derived as count >= 1, and the surface forms are the auditable spoken strings that feed schema.finance.fact.v1.

This module does not settle a fact. Role anchoring and the fail-closed Kalshi filter are the role parser’s job.

FunctionDescription
classify_mentions(transcript, term, *[, …])Classify each occurrence of term in transcript by compound type.
count_mentions(transcript, term, *[, …])Count term’s mentions in transcript (alias/phonetic-aware).
seed_initial_prompt(custom_strike_terms)Build a per-call faster-whisper initial_prompt from target terms.
ClassDescription
SttTranscriber([model_size, device, …])faster-whisper (CTranslate2) transcriber.
TranscriptResult(text[, segments, language, …])The joined transcript text + the per-segment records + model info.

class mostlyright.finance.transcripts.stt.SttTranscriber(model_size=‘large-v3’, , device=‘cpu’, compute_type=‘int8’)

Section titled “class mostlyright.finance.transcripts.stt.SttTranscriber(model_size=‘large-v3’, , device=‘cpu’, compute_type=‘int8’)”

Bases: object

faster-whisper (CTranslate2) transcriber.

model_size selects the tier: large-v3 default (the model the hosted path runs); small for the on-device earnings.live floor. device / compute_type mirror faster-whisper’s constructor (CPU int8 is the keyless/offline default). The WhisperModel is constructed lazily on first transcribe so importing this class needs no [earnings] extra.

  • Parameters:
    • model_size (str)
    • device (str)
    • compute_type (str)

transcribe(audio_path, , initial_prompt=None, target_terms=(), word_timestamps=False)

Section titled “transcribe(audio_path, , initial_prompt=None, target_terms=(), word_timestamps=False)”

Transcribe audio_path via faster-whisper.

Threads initial_prompt straight through to WhisperModel.transcribe(..., initial_prompt=...) for per-call vocabulary biasing. If initial_prompt is None but target_terms are given, the prompt is seeded from them via seed_initial_prompt(). Returns a TranscriptResult carrying the joined text (feeds count_mentions()) plus the per-segment records.

Each segment record carries text / start / end, the decode statistics the engine computes anyway (_SEGMENT_STAT_FIELDS — free confidence signal, always present, None when the engine does not report one), and words.

word_timestamps is opt-in (default off) because word-level alignment runs a second pass over each segment and measurably slows the decode. Off (the default), the flag is not passed to the engine at all and every segment’s words is None (“never asked”). On, each segment’s words is a list of {word, start, end, probability} records ([] when the engine aligned no words for that segment).

class mostlyright.finance.transcripts.stt.TranscriptResult(text, segments=, language=None, duration=None, language_probability=None)

Section titled “class mostlyright.finance.transcripts.stt.TranscriptResult(text, segments=, language=None, duration=None, language_probability=None)”

Bases: object

The joined transcript text + the per-segment records + model info.

language_probability is the engine’s confidence in the detected language (None when the engine does not report one). Fields are append-only — a consumer constructing this positionally keeps working.

mostlyright.finance.transcripts.stt.classify_mentions(transcript, term, , match_rule=‘plural_possessive_ok_no_tense’, asr_misrenders=False)

Section titled “mostlyright.finance.transcripts.stt.classify_mentions(transcript, term, , match_rule=‘plural_possessive_ok_no_tense’, asr_misrenders=False)”

Classify each occurrence of term in transcript by compound type.

A sibling of count_mentions(): returns one record per occurrence, each {"surface", "start", "compound_type"} where compound_type is one of standalone / open / hyphenated / closed / affix_derivation (the cross-venue compound divergence). It reuses the same form expansion + apostrophe + plural/ possessive machinery as count_mentions() (_match_forms_for_term + _form_to_pattern) — never bare exact equality — so a possessive (tariff's) is a standalone occurrence, not a miss.

The word-boundary pass finds standalone / open / hyphenated occurrences exactly as count_mentions counts them; pre-tariff is a real occurrence, tagged hyphenated. A second, substring pass finds closed candidates — a surface form fused inside a longer word component where the term stays a distinct part (wildfire, killjoy, and the wildfire component of wildfire-related — hyphenated tokens are split and each component scanned) — and separates true closed compounds from affix_derivation roots (joyful, incl. inside hyphenated tokens: joyful-sounding) via a curated stdlib suffix heuristic (_closed_or_affix(); no dictionary dependency). The heuristic is conservative: an ambiguous case becomes a closed candidate for a human reviewer, never a silent drop.

Overlap handling matches count_mentions: longest-first, and a span is classified once (the word-boundary occurrences win; a closed substring pass skips any span already covered so pre-tariff is not double-counted as both hyphenated and closed).

Raises ValueError for an unrecognized match_rule or a degenerate term — identically to count_mentions() (shared _validated_forms_for_term() path): silently returning [] would settle “not mentioned” on a config bug.

mostlyright.finance.transcripts.stt.count_mentions(transcript, term, , match_rule=‘plural_possessive_ok_no_tense’, asr_misrenders=False)

Section titled “mostlyright.finance.transcripts.stt.count_mentions(transcript, term, , match_rule=‘plural_possessive_ok_no_tense’, asr_misrenders=False)”

Count term’s mentions in transcript (alias/phonetic-aware).

Returns (mention_count, matched_surface_forms). The integer is the primary tally that earnings-mention markets settle on; the boolean (“said at least once”) is derived by the caller as count >= 1. matched_surface_forms are the actually spoken strings, verbatim and in order, so each occurrence is auditable against each venue’s stricter or looser rule; they feed schema.finance.fact.v1.matched_surface_form.

Matching is never bare exact string equality: slash-synonyms, English plural and possessive forms (under plural_possessive_ok_no_tensecompany/companies/company's, data center/data centers), and acronym plurals and possessives (APIs, API's) all count. Hyphenated compounds count for the bare term on both venues (pre-tariff, tariff-based, non-fat, and pro-Palestine count for tariff, fat, and Palestine; the Kalshi and Polymarket PDFs are quoted verbatim in _form_to_pattern()). Verb-tense inflections (tariffed) do not count. A closed (unhyphenated) compound (wildfire for fire) does not count via count_mentions; the closed-compound cross-venue divergence is tagged per-occurrence by classify_mentions(). Spelled-out separator forms (O-C-I / O.C.I / O C I) are not matched, because they false-positive on short acronyms and longer spelled sequences; acronym emission relies on initial_prompt biasing instead.

asr_misrenders, off by default, opts in to the known STT mis-render aliases (OCR and OCIP for OCI). Leave it off unless the caller knows the engine mis-rendered the target acronym: OCR is a legitimate standalone term, so aliasing it unconditionally over-counts.

Raises ValueError for an unrecognized match_rule (only plural_possessive_ok_no_tense and exact are accepted), an empty term, a term that expands to no surface forms (a bare synonym separator " / "), or a term whose every surface form is word-character- free (a lone punctuation char "/" / "." / "-" / "&", which survives as its own form but can never match a word-boundary-anchored pattern). A typo’d rule fails loud rather than silently falling through to exact semantics and changing the settlement tally, and so does a term that would count 0 for every transcript and settle a market “not mentioned” on a config bug.

Known limitation, inherent to matching on spelling: a noun whose regular plural is spelled identically to its present-tense verb (cost -> costs, guide -> guides, result -> results) counts a verb-only usage (“it costs a lot”) as a plural-noun mention. The no_tense rule excludes +ed and +ing verb inflections, but a plural-noun and present-tense homograph is indistinguishable without part-of-speech tagging. The plural surface is accepted because the noun plural is the far more common, settlement-relevant usage in prepared remarks.

mostlyright.finance.transcripts.stt.seed_initial_prompt(custom_strike_terms)

Section titled “mostlyright.finance.transcripts.stt.seed_initial_prompt(custom_strike_terms)”

Build a per-call faster-whisper initial_prompt from target terms.

Vocabulary biasing: seeding the live market’s custom_strike words into the prompt makes the model far likelier to emit the exact jargon token, which mitigates the single-utterance rare-acronym miss. Slash-synonyms are exploded so each alternative surface form is a distinct seeded token. Returns "" for an empty term list.

  • Return type: str
  • Parameters: custom_strike_terms (list [str ])