Commit Graph

5 Commits

Author SHA1 Message Date
EJClaw
04664ce61a perf(brain): switch voice brain to Sonnet 5 with an always-on brevity rule
Sonnet 5 reaches first token ~0.4s sooner than Sonnet 4.5 but answers the
same voice prompt more verbosely (measured 46-54 vs ~28 output tokens),
which erased the win in total turn time. Add a cached, persona-independent
brevity system block that pulls output back to ~30 tokens, so the faster
first token becomes a faster, lower-variance whole reply.

Measured (16-round interleaved A/B, production-shaped call):
  sonnet-4-5      TTFT 1.26s  total 2.02s (tail 3.26s)  out 29
  sonnet-5+brev   TTFT 0.85s  total 1.70s (tail 2.28s)  out 30

- ClaudeBrain: default model claude-sonnet-5 + BREVITY block (cached with
  the persona prefix so a dashboard persona edit can't drop it).
- Defaults aligned: config.Settings.anthropic_model and the voice-server
  WSAI_BRAIN_MODEL default -> claude-sonnet-5.
- Dashboard: add claude-sonnet-5 to LLM_OPTIONS + JS label; fix stale
  restart hint.
- tests/latency_ab.py: reproducible model-latency A/B harness (reads
  CLAUDE_CREDENTIALS_PATH; makes live API calls, so not a pytest test).

Streaming TTS was intentionally not added: this bot answers in one sentence,
where sentence-level streaming has no overlap to exploit, and it would
require rearchitecting both the Python endpoint and the node playback.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-28 20:57:01 +09:00
EJClaw
63fcfb7ba2 feat(stt): real Korean STT via persistent faster-whisper worker
Step 3 (귀): add WhisperSTT + whisper_worker, a warm out-of-venv worker
mirroring the MeloTTS shape (whisper312 venv, small/int8 on CPU). transcribe()
closes the voice round trip (MeloTTS wav -> whisper text); utterances() turns an
injected audio_source into Utterances (Discord voice feed pending). Wired into
factory as WSAI_STT=whisper.

Also address the arbiter's TTS follow-ups:
- melo worker error handling: capture stderr (drained in a bounded background
  task so the pipe can't fill), surface the real failure cause, and defend
  against an empty/invalid ready line instead of dying on JSONDecodeError.
- pipeline pre-warm: load slow backends (warmup()) at startup so the first
  utterance is answered warm; a warmup failure is logged, not fatal.

Verified: real TTS->STT round trip recovers the sentence near-perfectly;
warm transcribe ~1.2s (CPU). 12 tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-18 18:29:32 +09:00
EJClaw
6a138eff3a feat(tts): real Korean TTS via persistent MeloTTS worker
Adds a MeloTTS backend that runs the model in its own melo311 interpreter
as a long-lived worker (melo_worker.py), loaded once and fed synthesis
requests over a stdin/stdout JSON protocol. fd1 is split from fd2 in the
worker so MeloTTS's stdout progress chatter can't corrupt the protocol.
Each speak() writes a wav and hands the path to a pluggable sink (the
Discord voice step will swap in "play into the call"). factory wires
tts=melo; pipeline.aclose now also tears down the tts worker.

Verified (CPU): model load ~7.9s once, then a short reply synthesizes in
~0.86s (within the ~1s budget); wav is valid 44.1kHz PCM. GPU (cuda) is
selectable via WSAI_MELO_DEVICE for lower latency, pending GPU approval.
7 smoke tests still pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-18 18:14:44 +09:00
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
claude-owner
4eeddc4b1f 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).
2026-08-09 02:16:14 +09:00