Files
watch_sceen_ai/wsai/factory.py
EJClaw 2b6059141e 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>
2026-08-11 00:05:02 +09:00

75 lines
1.8 KiB
Python

"""Build a Pipeline from Settings. This is the single place that knows which
concrete class each config name maps to, so adding a backend = one line here."""
from __future__ import annotations
from .config import Settings
from .pipeline import Pipeline
def build(settings: Settings) -> Pipeline:
return Pipeline(
source=_source(settings),
vision=_vision(settings),
brain=_brain(settings),
stt=_stt(settings),
tts=_tts(settings),
text_channel=_text(settings),
)
def _source(s: Settings):
if s.source in (None, "none"):
return None
if s.source == "mss":
from .backends.capture_mss import MSSFrameSource
return MSSFrameSource(interval=s.capture_interval)
from .backends.mock import MockFrameSource
return MockFrameSource(interval=s.capture_interval)
def _vision(s: Settings):
if s.vision in (None, "none"):
return None
if s.vision == "claude":
from .backends.claude import ClaudeVision
return ClaudeVision(model=s.anthropic_model)
from .backends.mock import MockVision
return MockVision()
def _brain(s: Settings):
if s.brain == "claude":
from .backends.claude import ClaudeBrain
return ClaudeBrain(model=s.anthropic_model)
from .backends.mock import MockBrain
return MockBrain()
def _stt(s: Settings):
if s.stt in (None, "none"):
return None
from .backends.mock import MockSTT
return MockSTT()
def _tts(s: Settings):
if s.tts in (None, "none"):
return None
from .backends.mock import MockTTS
return MockTTS()
def _text(s: Settings):
if s.text in (None, "none"):
return None
raise NotImplementedError("discord text channel backend not implemented yet")