Refactor exporter into modules
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import Counter, defaultdict
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from .utils import as_float, as_int
|
||||
|
||||
COST_FIELDS = ("input", "output", "cacheRead", "cacheWrite", "total")
|
||||
|
||||
|
||||
@dataclass
|
||||
class Totals:
|
||||
total: int = 0
|
||||
input: int = 0
|
||||
output: int = 0
|
||||
cache_read: int = 0
|
||||
cache_write: int = 0
|
||||
reasoning: int = 0
|
||||
entries: int = 0
|
||||
cost_input: float = 0.0
|
||||
cost_output: float = 0.0
|
||||
cost_cache_read: float = 0.0
|
||||
cost_cache_write: float = 0.0
|
||||
cost_total: float = 0.0
|
||||
|
||||
def add_usage(self, usage: dict) -> tuple[int, int, int, int, int, int, dict[str, float]]:
|
||||
total_tokens = as_int(usage.get("totalTokens"))
|
||||
input_tokens = as_int(usage.get("input"))
|
||||
output_tokens = as_int(usage.get("output"))
|
||||
cache_read_tokens = as_int(usage.get("cacheRead"))
|
||||
cache_write_tokens = as_int(usage.get("cacheWrite"))
|
||||
reasoning_tokens = as_int(usage.get("reasoningTokens"))
|
||||
|
||||
self.entries += 1
|
||||
self.total += total_tokens
|
||||
self.input += input_tokens
|
||||
self.output += output_tokens
|
||||
self.cache_read += cache_read_tokens
|
||||
self.cache_write += cache_write_tokens
|
||||
self.reasoning += reasoning_tokens
|
||||
|
||||
skipped_negative_costs: dict[str, float] = {}
|
||||
cost = usage.get("cost") or {}
|
||||
if isinstance(cost, dict):
|
||||
input_cost = as_float(cost.get("input"))
|
||||
output_cost = as_float(cost.get("output"))
|
||||
cache_read_cost = as_float(cost.get("cacheRead"))
|
||||
cache_write_cost = as_float(cost.get("cacheWrite"))
|
||||
total_cost = as_float(cost.get("total"))
|
||||
|
||||
if input_cost < 0:
|
||||
skipped_negative_costs["input"] = input_cost
|
||||
input_cost = 0.0
|
||||
if output_cost < 0:
|
||||
skipped_negative_costs["output"] = output_cost
|
||||
output_cost = 0.0
|
||||
if cache_read_cost < 0:
|
||||
skipped_negative_costs["cacheRead"] = cache_read_cost
|
||||
cache_read_cost = 0.0
|
||||
if cache_write_cost < 0:
|
||||
skipped_negative_costs["cacheWrite"] = cache_write_cost
|
||||
cache_write_cost = 0.0
|
||||
if total_cost < 0:
|
||||
skipped_negative_costs["total"] = total_cost
|
||||
total_cost = 0.0
|
||||
|
||||
self.cost_input += input_cost
|
||||
self.cost_output += output_cost
|
||||
self.cost_cache_read += cache_read_cost
|
||||
self.cost_cache_write += cache_write_cost
|
||||
self.cost_total += total_cost
|
||||
|
||||
return (
|
||||
total_tokens,
|
||||
input_tokens,
|
||||
output_tokens,
|
||||
cache_read_tokens,
|
||||
cache_write_tokens,
|
||||
reasoning_tokens,
|
||||
skipped_negative_costs,
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class UsageReport:
|
||||
today: Totals = field(default_factory=Totals)
|
||||
all_time: Totals = field(default_factory=Totals)
|
||||
files_scanned: int = 0
|
||||
lines_scanned: int = 0
|
||||
parse_errors: int = 0
|
||||
negative_cost_entries_skipped: int = 0
|
||||
negative_cost_fields_skipped: Counter[str] = field(default_factory=Counter)
|
||||
negative_cost_amounts_skipped: defaultdict[str, float] = field(default_factory=lambda: defaultdict(float))
|
||||
message_records_today: int = 0
|
||||
message_records_all_time: int = 0
|
||||
non_message_records_today: int = 0
|
||||
non_message_records_all_time: int = 0
|
||||
unique_session_ids_today: set[str] = field(default_factory=set)
|
||||
unique_models_today: set[str] = field(default_factory=set)
|
||||
unique_providers_today: set[str] = field(default_factory=set)
|
||||
role_counts_today: Counter[str] = field(default_factory=Counter)
|
||||
stop_reason_counts_today: Counter[tuple[str, str, str]] = field(default_factory=Counter)
|
||||
tool_call_counts_today: Counter[str] = field(default_factory=Counter)
|
||||
error_type_counts_today: Counter[str] = field(default_factory=Counter)
|
||||
session_message_counts_today: Counter[tuple[str, str]] = field(default_factory=Counter)
|
||||
session_error_counts_today: Counter[str] = field(default_factory=Counter)
|
||||
session_tool_call_counts_today: Counter[tuple[str, str]] = field(default_factory=Counter)
|
||||
tokens_by_model_today: defaultdict[tuple[str, str], int] = field(default_factory=lambda: defaultdict(int))
|
||||
input_tokens_by_model_today: defaultdict[tuple[str, str], int] = field(default_factory=lambda: defaultdict(int))
|
||||
output_tokens_by_model_today: defaultdict[tuple[str, str], int] = field(default_factory=lambda: defaultdict(int))
|
||||
reasoning_tokens_by_model_today: defaultdict[tuple[str, str], int] = field(default_factory=lambda: defaultdict(int))
|
||||
session_tokens_today: defaultdict[str, int] = field(default_factory=lambda: defaultdict(int))
|
||||
session_input_tokens_today: defaultdict[str, int] = field(default_factory=lambda: defaultdict(int))
|
||||
session_output_tokens_today: defaultdict[str, int] = field(default_factory=lambda: defaultdict(int))
|
||||
tokens_by_model_all_time: defaultdict[tuple[str, str], int] = field(default_factory=lambda: defaultdict(int))
|
||||
input_tokens_by_model_all_time: defaultdict[tuple[str, str], int] = field(default_factory=lambda: defaultdict(int))
|
||||
output_tokens_by_model_all_time: defaultdict[tuple[str, str], int] = field(default_factory=lambda: defaultdict(int))
|
||||
session_tokens_all_time: defaultdict[str, int] = field(default_factory=lambda: defaultdict(int))
|
||||
day_buckets: defaultdict[str, Totals] = field(default_factory=lambda: defaultdict(Totals))
|
||||
hour_buckets: defaultdict[str, Totals] = field(default_factory=lambda: defaultdict(Totals))
|
||||
|
||||
|
||||
@dataclass
|
||||
class SessionIndexReport:
|
||||
visible_count: int = 0
|
||||
total_count: int = 0
|
||||
has_more: bool = False
|
||||
sessions: list[dict] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
class UsageCostCacheReport:
|
||||
version: int | None = None
|
||||
updated_at_ms: int | None = None
|
||||
files_tracked: int = 0
|
||||
Reference in New Issue
Block a user