feat(dictate): add voice-reactive listening waveform

This commit is contained in:
jb
2026-08-26 13:40:47 -04:00
parent e234468a73
commit d1a811a5c5
16 changed files with 383 additions and 73 deletions
@@ -5,6 +5,7 @@ from __future__ import annotations
from collections.abc import Sequence
from concurrent.futures import Executor, Future, ThreadPoolExecutor
from dataclasses import dataclass
import math
import os
from queue import Empty, SimpleQueue
import selectors
@@ -30,9 +31,13 @@ from .recorder import Capture, PwRecorder, RecorderError
DEFAULT_IDLE_SECONDS = 15 * 60
MAX_CLIENT_CONNECTIONS = 16
MAX_CONNECTION_OUTPUT_BYTES = MAX_FRAME_BYTES
LEVEL_EVENT_INTERVAL_SECONDS = 0.1
class Recorder(Protocol):
@property
def audio_level(self) -> float: ...
def start(self) -> None: ...
def stop(self) -> Capture: ...
def cancel(self) -> None: ...
@@ -53,6 +58,7 @@ class _Generation:
state: str
recorder: Recorder | None = None
tombstoned: bool = False
last_level_event_at: float | None = None
@dataclass(frozen=True)
@@ -156,6 +162,8 @@ class DictateServiceCore:
if failure is not None:
self._async_error(active, failure.code, failure.detail)
self._finish_generation(active, notify_idle=True)
return
self._emit_audio_level(active)
def drain_events(self) -> list[Outbound]:
events, self._events = self._events, []
@@ -216,8 +224,31 @@ class DictateServiceCore:
self._finish_generation(active, notify_idle=True)
return
active.recorder = recorder
active.last_level_event_at = self._clock()
self._state(active, "listening")
def _emit_audio_level(self, active: _Generation) -> None:
now = self._clock()
if (
active.last_level_event_at is not None
and now - active.last_level_event_at < LEVEL_EVENT_INTERVAL_SECONDS
):
return
level = active.recorder.audio_level if active.recorder is not None else 0.0
if not math.isfinite(level):
level = 0.0
active.last_level_event_at = now
self._emit(
active.owner,
{
"version": PROTOCOL_VERSION,
"type": "level",
"requestId": active.request_id,
"generationId": active.generation_id,
"level": round(max(0.0, min(1.0, level)), 3),
},
)
def _stop(self, client_id: str, request: Request) -> None:
active = self._owned_generation(client_id, request)
if active is None:
@@ -433,7 +464,7 @@ def inherited_listener(environ: dict[str, str] | None = None) -> socket.socket:
def serve(listener: socket.socket, core: DictateServiceCore) -> None:
"""Serve protocol v1 on an explicit listener until the core becomes idle."""
"""Serve protocol v2 on an explicit listener until the core becomes idle."""
selector = selectors.DefaultSelector()
connections: dict[str, _Connection] = {}
sequence = 0