feat(dashboard): show Claude usage per day/week instead of per session

Persists per-day token usage (usage_store, ~/.config/wsai/usage.json, survives
restarts) and surfaces it in status as claude_usage.{today,week}. The navbar now
shows two cards — 오늘 토큰 / 주간 토큰 (input+output, with per-card tooltips
breaking down input/output tokens and requests) — replacing the session-only
token count.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
EJClaw
2026-08-22 22:20:30 +09:00
parent 7ea07c13ad
commit d1d4bd1514
3 changed files with 95 additions and 6 deletions

View File

@@ -726,7 +726,8 @@ PAGE = r"""<!DOCTYPE html>
<div class="stats">
<div class="stat"><b id="s-turns">0</b><span>대화 수</span></div>
<div class="stat"><b id="s-errors">0</b><span>오류</span></div>
<div class="stat" title="이 봇이 서버 시작 후 쓴 클로드 토큰"><b id="s-claude">0</b><span>클로드 토큰</span></div>
<div class="stat" title="오늘 사용한 클로드 토큰(입력+출력)"><b id="s-claude-today">0</b><span>오늘 토큰</span></div>
<div class="stat" title="최근 7일 사용한 클로드 토큰(입력+출력)"><b id="s-claude-week">0</b><span>주간 토큰</span></div>
<div class="stat"><b id="s-up">0초</b><span>가동시간</span></div>
<div class="stat"><b id="s-conn">·</b><span>연결</span></div>
</div>
@@ -822,10 +823,14 @@ function renderStatus(s){
$('s-turns').textContent = s.turns_total ?? 0;
$('s-errors').textContent = s.errors_total ?? 0;
$('s-up').textContent = fmtUptime(s.uptime_s);
const ci=s.claude_input_tokens||0, co=s.claude_output_tokens||0, cr=s.claude_requests||0;
const cel=$('s-claude');
if(cel){ cel.textContent = fmtNum(ci+co);
cel.parentElement.title = '클로드 사용량 (서버 시작 후) — 입력 '+ci.toLocaleString()+' · 출력 '+co.toLocaleString()+' 토큰 · 요청 '+cr+''; }
const cu = s.claude_usage || {today:{input:0,output:0,requests:0}, week:{input:0,output:0,requests:0}};
const td=cu.today||{}, wk=cu.week||{};
const te=$('s-claude-today');
if(te){ te.textContent = fmtNum((td.input||0)+(td.output||0));
te.parentElement.title = '오늘 클로드 — 입력 '+(td.input||0).toLocaleString()+' · 출력 '+(td.output||0).toLocaleString()+' 토큰 · 요청 '+(td.requests||0)+''; }
const we=$('s-claude-week');
if(we){ we.textContent = fmtNum((wk.input||0)+(wk.output||0));
we.parentElement.title = '최근 7일 클로드 — 입력 '+(wk.input||0).toLocaleString()+' · 출력 '+(wk.output||0).toLocaleString()+' 토큰 · 요청 '+(wk.requests||0)+''; }
const listening = s.listening;
$('dot').className = 'dot ' + (listening ? 'live' : 'off');
$('listen').textContent = listening ? '듣는 중' : (s.running ? '실행 중 (대기)' : '중지됨');