feat(dashboard): per-stage STT/LLM/TTS timing + rename 두뇌 -> LLM
- voice_turn now records three separate timed steps (STT, LLM, TTS) instead of one combined "STT+두뇌+TTS" step, so each stage's latency shows in the turn. - Rename 두뇌 -> LLM everywhere user-facing: component chip, sub header, demo banner, model label, brain-failure log, startup print, pipeline step name. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -650,6 +650,13 @@ class Dashboard:
|
||||
self.monitor.log("info", f"LLM 모델 변경: {model} (다음 답변부터 적용)", cat="MODEL")
|
||||
return {**self.models_settings()["llm"], "changed": changed}
|
||||
|
||||
@staticmethod
|
||||
def _step(turn, name: str, ms: float) -> None:
|
||||
"""Record one finished timing step (STT / LLM / TTS) on a turn."""
|
||||
st = turn.step(name)
|
||||
st.ok, st.ms = True, float(ms)
|
||||
turn._steps.append(st)
|
||||
|
||||
def voice_turn(self, audio_bytes: bytes, speaker: str = "",
|
||||
guild: str = "", channel: str = "") -> dict:
|
||||
"""One Discord voice turn: decode the uploaded utterance, recognise it
|
||||
@@ -680,6 +687,7 @@ class Dashboard:
|
||||
check=True, capture_output=True,
|
||||
)
|
||||
heard = (self._submit(self.stt.transcribe(wav)) or "").strip()
|
||||
self._step(turn, "STT", (time.monotonic() - t0) * 1000) # 인식(+디코드)
|
||||
turn.heard(heard or "(빈 결과)")
|
||||
if not heard:
|
||||
# Nothing recognised (silence/noise): mark it as [잡음] and skip
|
||||
@@ -688,16 +696,16 @@ class Dashboard:
|
||||
turn.replied("[잡음]")
|
||||
turn.finish()
|
||||
return {"heard": heard, "reply": "[잡음]", "wav": b""}
|
||||
t_llm = time.monotonic()
|
||||
reply_text = self._think(heard)
|
||||
self._step(turn, "LLM" if self.brain else "echo", (time.monotonic() - t_llm) * 1000)
|
||||
turn.thought(_thought_summary(reply_text))
|
||||
turn.replied(reply_text)
|
||||
t_tts = time.monotonic()
|
||||
out_path = self._submit(self.tts.synth(_speech_text(reply_text)))
|
||||
with open(out_path, "rb") as f:
|
||||
reply_wav = f.read()
|
||||
ms = int((time.monotonic() - t0) * 1000)
|
||||
step = turn.step("STT+두뇌+TTS" if self.brain else "STT+TTS(GPU)")
|
||||
step.ok, step.ms = True, float(ms)
|
||||
turn._steps.append(step)
|
||||
self._step(turn, "TTS", (time.monotonic() - t_tts) * 1000) # 합성
|
||||
turn.finish()
|
||||
try:
|
||||
os.remove(out_path)
|
||||
@@ -733,7 +741,7 @@ class Dashboard:
|
||||
self.monitor.add_claude_usage(u.get("input", 0), u.get("output", 0))
|
||||
except Exception as exc: # noqa: BLE001
|
||||
log.exception("brain failed")
|
||||
self.monitor.log("error", f"두뇌 응답 실패: {exc}", cat="BRAIN")
|
||||
self.monitor.log("error", f"LLM 응답 실패: {exc}", cat="BRAIN")
|
||||
blob = f"{getattr(exc, 'status_code', '')} {exc}".lower()
|
||||
if "529" in blob or "overload" in blob:
|
||||
# Transient server overload survived the SDK retries.
|
||||
@@ -1008,7 +1016,7 @@ PAGE = r"""<!DOCTYPE html>
|
||||
<header>
|
||||
<div>
|
||||
<h1>watch_sceen_ai · 실시간 상태</h1>
|
||||
<div class="sub">STT → 두뇌 → TTS 음성 루프를 단계별로 관찰</div>
|
||||
<div class="sub">STT → LLM → TTS 음성 루프를 단계별로 관찰</div>
|
||||
</div>
|
||||
<div class="pill"><span id="dot" class="dot off"></span><span id="listen">연결 대기</span></div>
|
||||
<button id="promptBtn" class="btn hbtn">📝 프롬프트</button>
|
||||
@@ -1081,7 +1089,7 @@ PAGE = r"""<!DOCTYPE html>
|
||||
<span id="mSTTstat" class="sttstat"></span>
|
||||
</div>
|
||||
<div class="sttrow" style="margin-top:8px">
|
||||
<label style="font-size:12.5px;color:var(--muted)">LLM(두뇌)
|
||||
<label style="font-size:12.5px;color:var(--muted)">LLM
|
||||
<select id="mLLM" class="ttssel"></select></label>
|
||||
<button id="mLLMapply" class="btn">적용</button>
|
||||
<span id="mLLMstat" class="sttstat"></span>
|
||||
@@ -1194,14 +1202,14 @@ function renderStatus(s){
|
||||
const bar = $('demobar');
|
||||
if(mockParts.length){
|
||||
bar.style.display='block';
|
||||
bar.innerHTML = '⚠ <b>데모 모드</b> — 실제 음성/STT/두뇌/TTS가 아직 연결되지 않아, 아래 대화는 '
|
||||
bar.innerHTML = '⚠ <b>데모 모드</b> — 실제 음성/STT/LLM/TTS가 아직 연결되지 않아, 아래 대화는 '
|
||||
+ '실제로 들은 내용이 아니라 <b>목(mock) 예시 스크립트</b>입니다. '
|
||||
+ '실제 엔진(faster-whisper·Claude·MeloTTS)을 붙이면 이 자리에 진짜 발화·지연·오류가 표시됩니다.';
|
||||
} else {
|
||||
bar.style.display='none';
|
||||
}
|
||||
const el = $('comp'); el.innerHTML = '';
|
||||
const names = {source:'눈(소스)', vision:'시각', stt:'귀(STT)', brain:'두뇌', tts:'입(TTS)', text:'텍스트'};
|
||||
const names = {source:'눈(소스)', vision:'시각', stt:'귀(STT)', brain:'LLM', tts:'입(TTS)', text:'텍스트'};
|
||||
for(const k of Object.keys(names)){
|
||||
if(!(k in comps)) continue;
|
||||
const v = comps[k];
|
||||
|
||||
Reference in New Issue
Block a user