hearing.interfaces

Facade Protocols for the four pipeline concerns.

Every engine/component is dependency-injected as one of these; the pipeline depends only on these interfaces, never on a concrete engine. Implementers satisfy them structurally (typing.Protocol) — they do not subclass.

This is the contract the hearing-architecture skill defines and that every other hearing-* concern implements against.

Classes

AgentConsumer(*args, **kwargs)

Consumes the (labeled) transcript stream and does things.

CaptureSource(*args, **kwargs)

Audio source — the ONLY thing that differs between batch and live.

Diarizer(*args, **kwargs)

Labels who spoke — enriches segments with .speaker.

STTEngine(*args, **kwargs)

Speech-to-text.

class hearing.interfaces.AgentConsumer(*args, **kwargs)[source]

Bases: Protocol

Consumes the (labeled) transcript stream and does things.

Running notes, suggested questions, RAG over related docs, post-meeting summaries. Defaults to Claude but stays pluggable (see the claude-api skill for model ids / pricing / tool use).

async on_segment(segment)[source]

Called per finalized segment (live). Return an optional insight.

Return type:

Optional[str]

async on_window(window)[source]

Called on a window/turn or the whole transcript (batch).

Return an optional insight (summary, action items, a suggested question, a surfaced document, …).

Return type:

Optional[str]

class hearing.interfaces.CaptureSource(*args, **kwargs)[source]

Bases: Protocol

Audio source — the ONLY thing that differs between batch and live.

Yields (channel, frames) so mic and system audio stay on separate channels all the way down. A batch implementation reads a file; a live implementation reads a device/tap.

astream()[source]

Live / async: yield (channel, frames) blocks until stopped.

Return type:

AsyncIterator[tuple[Channel, Any]]

frames()[source]

Batch / sync: yield (channel, frames[n_samples]) blocks to EOF.

Return type:

Iterator[tuple[Channel, Any]]

class hearing.interfaces.Diarizer(*args, **kwargs)[source]

Bases: Protocol

Labels who spoke — enriches segments with .speaker.

May use the audio (pyannote) or just the channel (the channel trick). Identity resolution (spk_0 -> "Alice") is an optional further step behind the same interface.

assign_speakers(segments, *, audio=None, sample_rate=None)[source]

Yield segments with .speaker populated (enrich-by-copy).

Return type:

Iterable[TranscriptSegment]

class hearing.interfaces.STTEngine(*args, **kwargs)[source]

Bases: Protocol

Speech-to-text.

transcribe is the batch one-liner; stream_transcribe is the live variant. Both yield TranscriptSegment — same shape, same spine. The rest of the architecture never names a concrete engine.

async stream_transcribe(frames, *, sample_rate)[source]

Live: yield interim then finalized segments as audio arrives.

Mark interim vs final via meta (e.g. meta['final']). See the hearing-live-pipeline skill — this is the milestone-2 entry point.

Return type:

AsyncIterator[TranscriptSegment]

transcribe(audio, *, sample_rate, language=None)[source]

Batch: whole clip in (float32 mono ndarray), segments out.

Return type:

Sequence[TranscriptSegment]