-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathget_usage.py
More file actions
executable file
·127 lines (105 loc) · 4.37 KB
/
get_usage.py
File metadata and controls
executable file
·127 lines (105 loc) · 4.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/usr/bin/env python3
"""Read Claude Code token usage from session JSONL files and output a daily summary as JSON."""
import json
import sys
from collections import defaultdict
from datetime import date
from pathlib import Path
PROJECTS_DIR = Path.home() / ".claude" / "projects"
# Pricing per million tokens (USD)
# Cache read = 10% of input, cache create = 125% of input
PRICING = {
"opus": {"input": 5, "output": 25, "cache_read": 0.50, "cache_create": 6.25},
"sonnet": {"input": 3, "output": 15, "cache_read": 0.30, "cache_create": 3.75},
"haiku": {"input": 1, "output": 5, "cache_read": 0.10, "cache_create": 1.25},
}
DEFAULT_PRICING = PRICING["opus"]
def simplify_model_name(model_id: str) -> str:
"""Turn 'claude-opus-4-6' or 'claude-sonnet-4-5-20250929' into 'opus' / 'sonnet'."""
for short_name in ("opus", "sonnet", "haiku"):
if short_name in model_id:
return short_name
return model_id
def _cost(model: str, input_t: int, output_t: int, cache_read_t: int, cache_create_t: int) -> float:
"""Compute cost in USD for a set of tokens using per-model pricing."""
p = PRICING.get(model, DEFAULT_PRICING)
return (
input_t * p["input"]
+ output_t * p["output"]
+ cache_read_t * p["cache_read"]
+ cache_create_t * p["cache_create"]
) / 1_000_000
def get_usage(target_date: str | None = None) -> dict:
target = target_date or date.today().isoformat()
# Per-model accumulators: {model: {input, output, cache_read, cache_create}}
by_model: dict[str, dict[str, int]] = defaultdict(
lambda: {"input": 0, "output": 0, "cache_read": 0, "cache_create": 0}
)
message_count = 0
session_ids: set[str] = set()
if not PROJECTS_DIR.exists():
return _empty(target)
for jsonl_file in PROJECTS_DIR.rglob("*.jsonl"):
try:
with open(jsonl_file) as f:
for line in f:
obj = json.loads(line)
if obj.get("type") != "assistant":
continue
ts = obj.get("timestamp", "")
if not ts.startswith(target):
continue
msg = obj.get("message", {})
usage = msg.get("usage", {})
model = simplify_model_name(msg.get("model", "unknown"))
m = by_model[model]
m["input"] += usage.get("input_tokens", 0)
m["output"] += usage.get("output_tokens", 0)
m["cache_read"] += usage.get("cache_read_input_tokens", 0)
m["cache_create"] += usage.get("cache_creation_input_tokens", 0)
message_count += 1
sid = obj.get("sessionId", "")
if sid:
session_ids.add(sid)
except Exception:
continue
# Totals
total_input = sum(m["input"] for m in by_model.values())
total_output = sum(m["output"] for m in by_model.values())
total_cache_read = sum(m["cache_read"] for m in by_model.values())
total_cache_create = sum(m["cache_create"] for m in by_model.values())
# Cost per model and total
cost_by_model = {
model: round(_cost(model, m["input"], m["output"], m["cache_read"], m["cache_create"]), 4)
for model, m in by_model.items()
}
total_cost = round(sum(cost_by_model.values()), 4)
return {
"date": target,
"total_output_tokens": total_output,
"total_input_tokens": total_input,
"total_cache_read_tokens": total_cache_read,
"total_cache_creation_tokens": total_cache_create,
"output_by_model": {model: m["output"] for model, m in by_model.items()},
"total_cost_usd": total_cost,
"cost_by_model_usd": cost_by_model,
"messages": message_count,
"sessions": len(session_ids),
}
def _empty(target: str) -> dict:
return {
"date": target,
"total_output_tokens": 0,
"total_input_tokens": 0,
"total_cache_read_tokens": 0,
"total_cache_creation_tokens": 0,
"output_by_model": {},
"total_cost_usd": 0,
"cost_by_model_usd": {},
"messages": 0,
"sessions": 0,
}
if __name__ == "__main__":
target = sys.argv[1] if len(sys.argv) > 1 else None
result = get_usage(target)
print(json.dumps(result, indent=2))