feat: scaffold watch-screen AI pipeline (mock-runnable skeleton)

Modular async pipeline: FrameSource->Vision->context and STT/text->Brain->TTS.
All stages are Protocols; mock backends run end-to-end with no deps/keys.
Real backends included: mss screen capture, Claude vision+brain (guarded imports).
This commit is contained in:
claude-owner
2026-08-09 02:16:14 +09:00
parent 0c90856282
commit 4eeddc4b1f
15 changed files with 855 additions and 0 deletions

62
wsai/__main__.py Normal file
View File

@@ -0,0 +1,62 @@
"""Entry point.
python -m wsai # mock pipeline (no deps, no keys) — runs a demo
python -m wsai --live # capture this screen + Claude eyes/brain
python -m wsai --env # build from WSAI_* environment variables
The mock run is bounded (a few frames + a scripted conversation) so it exits on
its own; --live/--env run until Ctrl-C.
"""
from __future__ import annotations
import argparse
import asyncio
import logging
from .config import Settings
from .factory import build
async def _run(settings: Settings, demo: bool) -> None:
if demo:
# Bounded demo so CI / a quick check terminates.
from .backends.mock import MockFrameSource, MockSTT
from .pipeline import Pipeline
pipe = build(settings)
pipe.source = MockFrameSource(interval=0.3, limit=4)
if pipe.stt is not None:
pipe.stt = MockSTT(interval=0.4)
await pipe.run()
return
await build(settings).run()
def main() -> None:
ap = argparse.ArgumentParser(prog="wsai")
ap.add_argument("--live", action="store_true", help="capture screen + Claude backends")
ap.add_argument("--env", action="store_true", help="build from WSAI_* env vars")
ap.add_argument("-v", "--verbose", action="store_true")
args = ap.parse_args()
logging.basicConfig(
level=logging.DEBUG if args.verbose else logging.INFO,
format="%(levelname)s %(name)s: %(message)s",
)
if args.live:
settings, demo = Settings.live(), False
elif args.env:
settings, demo = Settings.from_env(), False
else:
settings, demo = Settings.mock(), True
try:
asyncio.run(_run(settings, demo))
except KeyboardInterrupt:
pass
if __name__ == "__main__":
main()