feat(voice): run pipeline eyes-free (STT -> Brain -> TTS), defer screen share

Make source/vision optional so the conversation loop runs with no screen
capture. Add Settings.voice() preset and `python -m wsai --voice` demo.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
EJClaw
2026-08-11 00:05:02 +09:00
parent b0780988a2
commit 2b6059141e
6 changed files with 60 additions and 12 deletions

View File

@@ -26,15 +26,16 @@ class Pipeline:
* perception: FrameSource -> VisionBackend -> SharedScreenContext
* conversation: (SpeechToText | TextChannel) -> Brain -> (TextToSpeech | TextChannel)
Either input/output half can be None, so you can run text-only, voice-only,
or a headless "just watch" configuration.
Any half can be omitted. With no source/vision it runs eyes-free as a pure
voice loop (STT -> Brain -> TTS); with no stt/tts it runs text-only; with no
conversation it is a headless "just watch" configuration.
"""
def __init__(
self,
*,
source: FrameSource,
vision: VisionBackend,
source: FrameSource | None = None,
vision: VisionBackend | None = None,
brain: Brain,
stt: SpeechToText | None = None,
tts: TextToSpeech | None = None,
@@ -53,6 +54,8 @@ class Pipeline:
# -- perception -------------------------------------------------------- #
async def _perceive(self) -> None:
if self.source is None or self.vision is None:
return # eyes-free (voice-only) configuration
async for frame in self.source.frames():
try:
obs = await self.vision.describe(frame)