hearing¶
hearing — pluggable meeting transcription & context-aware AI agents.
A small, composable toolkit for capturing, transcribing, and reasoning over meeting audio. Four swappable concerns compose into one pipeline by dependency injection: audio capture (mic + system audio on separate channels) -> STT engine facade (local or cloud) -> optional diarization / speaker-id (the mic-vs-system channel split gives “me vs them” for free) -> an agent layer that consumes the transcript (batch or live).
Progressive disclosure — the one-liner just works:
from hearing import transcribe
transcript = transcribe("meeting.wav")
print(transcript.formatted())
…while engine selection, diarization, agents, channel routing, and the live loop are all optional keyword-only arguments.
The architecture and the per-concern guidance live in the project’s agent skills
(.claude/skills/hearing*); start with the hearing skill.
Functions
|
Transcribe an audio source to a |
|
Stream FINALIZED segments as a meeting unfolds (the live path). |
|
Transcribe (if needed) then run an agent to produce meeting notes. |
Classes
|
A finished transcript: an ordered collection of segments plus metadata. |
|
The data spine — a standoff interval annotation over the audio. |
|
A half-open interval |
|
Optional word-level timing (WhisperX / |
|
Which capture channel a segment came from. |
- class hearing.Channel(*values)[source]¶
-
Which capture channel a segment came from.
The channel is the “me vs them” signal, for free:
MICis the local user,SYSTEMis everyone else (audio that came out of the speakers).MIXEDis a single-channel / unknown source.
- class hearing.TimeSpan(start_ms, end_ms)[source]¶
Bases:
objectA half-open interval
[start_ms, end_ms)in integer milliseconds.Integer time, never float seconds — accumulation-safe and hashable.
>>> TimeSpan(0, 1500).duration_ms 1500
- class hearing.Transcript(segments=(), sample_rate=None, meta=<factory>)[source]¶
Bases:
objectA finished transcript: an ordered collection of segments plus metadata.
Iterable and
len-able, so it stands in for aSequenceof segments wherever the architecture’s facades return “segments”. Adds convenience accessors the CLI/agents need.>>> t = Transcript((TranscriptSegment("a", TimeSpan(0, 1000), speaker=ME), ... TranscriptSegment("b", TimeSpan(1000, 2000), speaker=THEM))) >>> t.text 'a b' >>> len(t) 2 >>> sorted(t.speakers) ['me', 'them']
- formatted(*, speakers=True, timestamps=True)[source]¶
Render as a human-readable transcript, one line per segment.
- Return type:
- class hearing.TranscriptSegment(text, span, channel=Channel.MIXED, speaker=None, confidence=None, words=(), meta=<factory>)[source]¶
Bases:
objectThe data spine — a standoff interval annotation over the audio.
Required fields are
textandspan. Everything else is optional metadata that a concern enriches: STT setstext/span/confidence; capture setschannel; diarization setsspeaker. Segments are frozen — enrich by copying (with_speaker/with_channel), never mutate.>>> seg = TranscriptSegment("hello", TimeSpan(0, 500)) >>> seg.with_speaker(ME).speaker 'me' >>> seg.text 'hello'
- with_channel(channel)[source]¶
Return a copy carrying a channel label (frozen -> copy, don’t mutate).
- Return type:
- class hearing.Word(text, span, confidence=None)[source]¶
Bases:
objectOptional word-level timing (WhisperX /
word_timestamps=True).Lets an agent trigger on a keyword mid-utterance instead of waiting for the end of a turn. Purely optional metadata on a
TranscriptSegment.
- async hearing.live_transcribe(*, source, engine=None, diarizer=None, agent=None, audio_queue_max=50, segment_queue_max=100)[source]¶
Stream FINALIZED segments as a meeting unfolds (the live path).
Same components as
transcribe()— only the source (a streamingCaptureSourceinstead of a file) and the trigger cadence (VAD utterance turn-ends instead of run-once) change. TheSTTEngineandAgentConsumerinterfaces are unchanged.Each channel is demuxed onto its own bounded queue and driven through
engine.stream_transcribeas an independent async task, so a slow agent never stalls capture (backpressure) and the channel “me vs them” label rides every segment. Diarization defaults to the free channel trick; the agent’son_segmentis fired fire-and-forget. Yields segments as utterances finalize.See the
hearing-live-pipelineskill.
- hearing.summarize(source, *, agent=None, context=None, model=None, **transcribe_kwargs)[source]¶
Transcribe (if needed) then run an agent to produce meeting notes.
Accepts an audio source or an already-built
Transcript. Builds the default agent (Claude if available, else the offline extractive fallback) when none is injected.
- hearing.transcribe(source, *, engine=None, diarizer=None, agent=None, language=None, split=True, mic_channels=(0,), system_channels=(1,), record=None)[source]¶
Transcribe an audio source to a
Transcript.The one-liner
transcribe("meeting.wav")works with all defaults: the default local engine (faster-whisper), automatic channel splitting when the file is multi-channel, and the free “me vs them” channel-trick diarizer.- Parameters:
source (
str|Path|CaptureSource) – a file path or anyCaptureSource.engine (
Optional[STTEngine]) – STT engine (default: faster-whisper). Inject anySTTEngine.diarizer (
Optional[Diarizer]) – speaker labeller.None-> the channel trick is applied automatically when channel info is present (mic=”me”, system=”them”). Inject aPyannoteDiarizerto separate individual remote speakers.agent (
Optional[AgentConsumer]) – optionalAgentConsumerrun over the finished transcript (batch). Its output is stored undertranscript.meta['insight'].language (
Optional[str]) – force a language code (e.g. “en”);None= auto-detect.split (
bool) – split mic/system channels when the source is multi-channel.system_channels (
Sequence[int]) – column indices for the channel split.record – optional
MutableMappingstore (e.g. a dol store) to persist the transcript JSON under key"<source>.transcript.json".
- Return type:
- Returns:
A
Transcript(iterable/len-able, so it stands in for a sequence of segments). Segments carry text, span, channel, and speaker.
Modules
The agent / "copilot" layer — the actual point of the hearing project. |
|
Extra scribed backends that hearing contributes: Apple-Silicon MLX and WhisperX. |
|
Audio capture and channel handling for the hearing pipeline. |
|
Command-line interface for hearing, dispatched with |
|
Context stores and retrieval (RAG) for context-connected agents. |
|
Diarization and speaker labelling for the hearing pipeline. |
|
Facade Protocols for the four pipeline concerns. |
|
Pipeline assembly — compose the four concerns by dependency injection. |
|
Transcript persistence via key-value stores (python-storage / |
|
Speech-to-text for hearing — now backed by the scribed transcription façade. |
|
Shared data model for the hearing pipeline. |
|
Voice-activity detection and utterance segmentation — re-exported from scribed. |