diff --git a/daemon/claude_usage_daemon_windows.py b/daemon/claude_usage_daemon_windows.py index e615b7d..2343383 100644 --- a/daemon/claude_usage_daemon_windows.py +++ b/daemon/claude_usage_daemon_windows.py @@ -90,6 +90,7 @@ def compute_today_usage() -> dict: today = datetime.date.today() midnight = datetime.datetime.combine(today, datetime.time.min) total_tokens = 0 + output_tokens = 0 cost = 0.0 messages = 0 try: @@ -133,13 +134,15 @@ def compute_today_usage() -> dict: cw = usage.get("cache_creation_input_tokens", 0) or 0 cr = usage.get("cache_read_input_tokens", 0) or 0 total_tokens += inp + out + cw + cr + output_tokens += out messages += 1 p = _price_for(msg.get("model")) cost += (inp * p["in"] + out * p["out"] + cw * p["cache_w"] + cr * p["cache_r"]) / 1_000_000 except OSError: continue - return {"tk": int(total_tokens), "tc": int(round(cost * 100)), "tn": messages} + return {"tk": int(total_tokens), "tc": int(round(cost * 100)), + "tn": messages, "to": int(output_tokens)} def _build_file_logger() -> logging.Logger | None: diff --git a/firmware/src/data.h b/firmware/src/data.h index 42421bc..f67be3b 100644 --- a/firmware/src/data.h +++ b/firmware/src/data.h @@ -13,6 +13,7 @@ struct UsageData { // Today's Claude Code usage (Phase 4 — computed by the daemon from local // transcripts). Tokens can exceed 2^31 on a heavy day, so use 64-bit. long long tokens_today; // total tokens today (input+output+cache) + long long output_today; // output tokens today (what Claude generated) int cost_cents_today; // equivalent API cost today, US cents - int messages_today; // assistant messages today + int messages_today; // assistant requests (API turns) today }; diff --git a/firmware/src/main.cpp b/firmware/src/main.cpp index 885c4af..55351e2 100644 --- a/firmware/src/main.cpp +++ b/firmware/src/main.cpp @@ -113,6 +113,7 @@ static bool parse_json(const char* json, UsageData* out) { strlcpy(out->status, doc["st"] | "unknown", sizeof(out->status)); out->ok = doc["ok"] | false; out->tokens_today = doc["tk"] | (long long)0; + out->output_today = doc["to"] | (long long)0; out->cost_cents_today = doc["tc"] | 0; out->messages_today = doc["tn"] | 0; out->valid = true; diff --git a/firmware/src/ui.cpp b/firmware/src/ui.cpp index 7704cee..3f22b06 100644 --- a/firmware/src/ui.cpp +++ b/firmware/src/ui.cpp @@ -132,6 +132,7 @@ static lv_obj_t* bt_mac_lbl; static lv_obj_t* session_container; // today's tokens / cost static lv_obj_t* sess_cost_lbl; static lv_obj_t* sess_tokens_lbl; +static lv_obj_t* sess_gen_lbl; static lv_obj_t* sess_msgs_lbl; // App registry — the launcher renders one tile per entry, so adding a screen is @@ -704,25 +705,31 @@ static void init_session_screen(lv_obj_t* scr) { lv_label_set_text(sess_cost_lbl, "$0.00"); lv_obj_set_style_text_font(sess_cost_lbl, &font_tiempos_56, 0); lv_obj_set_style_text_color(sess_cost_lbl, COL_TEXT, 0); - lv_obj_align(sess_cost_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 30); + lv_obj_align(sess_cost_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 25); lv_obj_t* sub = lv_label_create(session_container); lv_label_set_text(sub, "spent today"); lv_obj_set_style_text_font(sub, &font_styrene_20, 0); lv_obj_set_style_text_color(sub, COL_DIM, 0); - lv_obj_align(sub, LV_ALIGN_TOP_MID, 0, L.content_y + 110); + lv_obj_align(sub, LV_ALIGN_TOP_MID, 0, L.content_y + 105); sess_tokens_lbl = lv_label_create(session_container); lv_label_set_text(sess_tokens_lbl, "\xE2\x80\x94 tokens"); lv_obj_set_style_text_font(sess_tokens_lbl, &font_styrene_28, 0); lv_obj_set_style_text_color(sess_tokens_lbl, COL_ACCENT, 0); - lv_obj_align(sess_tokens_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 165); + lv_obj_align(sess_tokens_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 152); + + sess_gen_lbl = lv_label_create(session_container); + lv_label_set_text(sess_gen_lbl, "\xE2\x80\x94 generated"); + lv_obj_set_style_text_font(sess_gen_lbl, &font_styrene_16, 0); + lv_obj_set_style_text_color(sess_gen_lbl, COL_DIM, 0); + lv_obj_align(sess_gen_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 192); sess_msgs_lbl = lv_label_create(session_container); lv_label_set_text(sess_msgs_lbl, "\xE2\x80\x94 requests"); lv_obj_set_style_text_font(sess_msgs_lbl, &font_styrene_20, 0); lv_obj_set_style_text_color(sess_msgs_lbl, COL_DIM, 0); - lv_obj_align(sess_msgs_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 215); + lv_obj_align(sess_msgs_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 232); lv_obj_add_flag(session_container, LV_OBJ_FLAG_HIDDEN); } @@ -805,6 +812,8 @@ void ui_update(const UsageData* data) { data->cost_cents_today / 100, data->cost_cents_today % 100); format_tokens(data->tokens_today, buf, sizeof(buf)); lv_label_set_text_fmt(sess_tokens_lbl, "%s tokens", buf); + format_tokens(data->output_today, buf, sizeof(buf)); + lv_label_set_text_fmt(sess_gen_lbl, "%s generated", buf); lv_label_set_text_fmt(sess_msgs_lbl, "%d requests", data->messages_today); } }