Commit Graph

7 Commits

Author SHA1 Message Date
EJClaw
df07224feb feat(dashboard): live-editable bot prompt via popup (view/edit/save)
Adds a persisted, runtime-editable system prompt. The brain reads the persona
on every turn (prompt_store.get_persona), so a dashboard edit applies to the
next reply with no restart; blank clears the override back to the built-in
PERSONA. New endpoints GET/POST /api/prompt, and a reusable modal popup
(뒤로가기 + 수정/저장) that later white/blacklist features will share.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-22 11:20:57 +09:00
EJClaw
4db73bf69f feat(voice): express [감정] tags via pitch/speed instead of speaking them
Emotion tags now steer delivery rather than being read aloud. parse_segments()
splits a reply on [감정] tags: a recognised emotion word switches the pitch and
speed of the text that follows (and is dropped), while a non-emotion bracket
(e.g. [1번]) keeps its inner words as spoken content. Emotions can change
mid-reply, so a single turn is synthesised as several pitch-shifted segments and
concatenated in the melo worker (librosa pitch_shift, warmed at startup).

The emotion vocabulary is grounded in Azure Neural TTS speaking styles plus
Ekman's basic emotions, with Korean synonyms. The brain persona is updated to
emit inline tags from that set.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-22 10:14:49 +09:00
EJClaw
f585ed7b76 feat(voice): bracketed emotion tags, [잡음] for noise, spoken emotion, concise replies
- Brain persona now prefixes every reply with one bracketed emotion tag
  (e.g. [반가움], [궁금]) and keeps replies to one or two short sentences.
- Empty/unrecognised audio (silence/noise) is reported as reply "[잡음]" with
  no TTS playback instead of an empty reply.
- TTS speaks the bracketed emotion too: "[힘차게] 안녕!" is synthesised as
  "힘차게, 안녕!" via a leading-tag -> spoken-word transform.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-22 01:44:25 +09:00
EJClaw
356d1128fa fix(voice): stop backtick TTS crash and actually count error turns
Claude replies with markdown/backticks by default; MeloTTS's Korean text
normaliser has no entry for '`' and dies with KeyError: '`', so any reply
mentioning a command/code block crashed the whole voice turn (500 on
/api/voice-turn). Fix at the shared synth() choke point with
normalize_for_speech(), which flattens code fences/inline code/links/markdown
and guarantees no backtick reaches the worker — covering both the dashboard
voice turn and the Discord speak() bridge. Also add a PERSONA line asking the
model to avoid markdown (belt-and-suspenders; the code strip is the real fix).

errors_total never moved for turn-level failures: it was only bumped by
log("error") events, and the dashboard voice path calls turn.finish(error=...)
without logging. Emit one error-level log event from Turn.finish() when a turn
ends in error, so both the server counter and the browser SSE mirror stay
consistent, guarded to count at most once. Drop the now-redundant pipeline
log("error") to avoid double counting and remove the dead _publish stub.

Verified: raw backtick -> worker KeyError '`' reproduced; after fix real
MeloTTS synth of a backtick+fenced reply succeeds; /api/voice-turn returns 200
with a wav body on a backtick reply and errors_total stays 0, and an induced
synth failure returns 500 with errors_total incrementing to exactly 1. Full
suite 18 passed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-18 23:29:13 +09:00
EJClaw
ee6f6b7f55 fix(brain): ride out transient Claude 529 overloads
A single Claude 529 Overloaded dropped the voice turn straight to the apology
fallback. The anthropic SDK retries >=500/429 but only twice by default, which
a busy window can outlast. Raise max_retries (WSAI_BRAIN_MAX_RETRIES, default 4)
so transient overloads recover silently, and give overloads their own spoken
fallback ("서버가 붐벼서...") distinct from generic failures. Kept modest so a
sustained outage still fails fast instead of leaving the bot silent.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-18 23:09:36 +09:00
EJClaw
4898192ae1 feat(brain): real Claude backend via Max OAuth token (auth_token + Claude Code system block)
Wires the deployment's Claude Max login (OAuth token from
$CLAUDE_CREDENTIALS_PATH) into ClaudeBrain/ClaudeVision. OAuth tokens
authenticate as Bearer (auth_token=), not x-api-key, and only answer
when the first system block is the Claude Code identity string, so the
real persona moves to a second system block. Token is re-read per
request so a host-side refresh is picked up without a restart. Falls
back to ANTHROPIC_API_KEY when set.

Verified: WSAI_BRAIN=claude returns a real Korean reply through the
factory; 7 smoke tests still pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-18 18:05:18 +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