-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathusage.py
More file actions
113 lines (98 loc) · 4.04 KB
/
Copy pathusage.py
File metadata and controls
113 lines (98 loc) · 4.04 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
import json
import os
import threading
from pathlib import Path
from typing import Any, Dict
_usage_lock = threading.Lock()
# Map model slug to (input_price_per_1M, output_price_per_1M) — OpenAI public pricing
PRICING = {
# GPT-4o family
"gpt-4o": (2.50, 10.00),
"gpt-4o-vision": (2.50, 10.00),
"gpt-4o-mini": (0.15, 0.60),
"gpt-4o-mini-vision": (0.15, 0.60),
# GPT-4 Turbo
"gpt-4-turbo": (10.00, 30.00),
"gpt-4-turbo-vision": (10.00, 30.00),
# GPT-5 family (estimates — not publicly priced yet)
"gpt-5-5": (5.00, 30.00),
"gpt-5-3": (5.00, 30.00),
"gpt-5-5-mini": (0.15, 0.60),
"gpt-5-3-mini": (0.15, 0.60),
"gpt-5-mini": (0.15, 0.60),
"gpt-5-5-vision": (5.00, 30.00),
"gpt-5-3-vision": (5.00, 30.00),
# Auto (weighted estimate)
"auto": (2.50, 10.00),
}
# Fallback default pricing if model is not specifically listed above
DEFAULT_PRICING = (2.50, 10.00)
def get_usage_file() -> Path:
usage_path = Path(__file__).resolve().parent.parent.parent / ".codex" / "usage.json"
usage_path.parent.mkdir(parents=True, exist_ok=True)
return usage_path
def load_usage() -> Dict[str, Any]:
usage_file = get_usage_file()
if not usage_file.exists():
return {
"total_requests": 0,
"total_input_tokens": 0,
"total_output_tokens": 0,
"total_savings_usd": 0.0,
"models": {}
}
try:
with open(usage_file, "r") as f:
return json.load(f)
except Exception:
# If file is corrupted or empty
return {
"total_requests": 0,
"total_input_tokens": 0,
"total_output_tokens": 0,
"total_savings_usd": 0.0,
"models": {}
}
def save_usage(data: Dict[str, Any]) -> None:
usage_file = get_usage_file()
temporary_file = usage_file.with_suffix(".json.tmp")
with temporary_file.open("w", encoding="utf-8") as handle:
json.dump(data, handle, indent=2)
handle.flush()
os.fsync(handle.fileno())
os.replace(temporary_file, usage_file)
def record_usage(model_slug: str, input_tokens: int, output_tokens: int, ttft_s: float = 0.0, generation_time_s: float = 0.0) -> None:
with _usage_lock:
data = load_usage()
# Pricing calculation
in_price_1m, out_price_1m = PRICING.get(model_slug, DEFAULT_PRICING)
cost = (input_tokens / 1_000_000) * in_price_1m + (output_tokens / 1_000_000) * out_price_1m
# Update totals
data["total_requests"] = data.get("total_requests", 0) + 1
data["total_input_tokens"] = data.get("total_input_tokens", 0) + input_tokens
data["total_output_tokens"] = data.get("total_output_tokens", 0) + output_tokens
data["total_savings_usd"] = data.get("total_savings_usd", 0.0) + cost
# Update model specifics
if "models" not in data:
data["models"] = {}
if model_slug not in data["models"]:
data["models"][model_slug] = {
"requests": 0,
"input_tokens": 0,
"output_tokens": 0,
"total_ttft_s": 0.0,
"total_generation_s": 0.0
}
data["models"][model_slug]["requests"] += 1
data["models"][model_slug]["input_tokens"] += input_tokens
data["models"][model_slug]["output_tokens"] += output_tokens
data["models"][model_slug]["total_ttft_s"] = data["models"][model_slug].get("total_ttft_s", 0.0) + ttft_s
data["models"][model_slug]["total_generation_s"] = data["models"][model_slug].get("total_generation_s", 0.0) + generation_time_s
save_usage(data)
def format_tokens(num: int) -> str:
"""Format token count in K or M for sleek display."""
if num >= 1_000_000:
return f"{num / 1_000_000:.1f}M"
elif num >= 1_000:
return f"{num / 1_000:.1f}K"
return str(num)