Metadata-Version: 2.4
Name: llm-usage-report
Version: 0.1.1
Summary: Parse LLM API response logs (Anthropic, OpenAI, Google) and generate token / cost reports. Supports a --alert-at budget alarm that exits non-zero when total cost exceeds a threshold. No framework adoption required.
Project-URL: Homepage, https://github.com/MukundaKatta/llm-usage-report
Project-URL: Issues, https://github.com/MukundaKatta/llm-usage-report/issues
Project-URL: Source, https://github.com/MukundaKatta/llm-usage-report
Author-email: Mukunda Katta <mukundkst@gmail.com>
License: MIT
License-File: LICENSE
Keywords: anthropic,billing,claude,cli,cost,gemini,google,llm,openai,tokens,usage
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Logging
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# llm-usage-report

[![CI](https://github.com/MukundaKatta/llm-usage-report/actions/workflows/ci.yml/badge.svg)](https://github.com/MukundaKatta/llm-usage-report/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/llm-usage-report.svg)](https://pypi.org/project/llm-usage-report/)
[![Python](https://img.shields.io/pypi/pyversions/llm-usage-report.svg)](https://pypi.org/project/llm-usage-report/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)

Parse LLM API response logs (Anthropic, OpenAI, Google) and generate a readable usage + cost report. Works on raw JSONL you already have sitting in log files — no framework adoption, no SDK wrapping, no proxy.

## Install

```bash
pip install llm-usage-report
```

## What it does

Point it at one or more JSONL files (or stdin), it reads the `usage` / `usageMetadata` fields from each line, normalizes them, and prints a table like:

```
model              requests  input   output  cache_read  cache_new  cost (USD)
-----------------  --------  ------  ------  ----------  ---------  ----------
claude-opus-4-5           8  120000   35000       20000      50000      $4.57
claude-sonnet-4-5        42   88000   32000           0          0      $0.75
gpt-4o                   15   45000   12000           0          0      $0.23
gemini-2.5-pro            6    8000    3000           0          0      $0.05
-----------------  --------  ------  ------  ----------  ---------  ----------
TOTAL                    71  261000   82000       20000      50000      $5.60
```

## Supported providers

| Provider | Shape it understands |
|---|---|
| **Anthropic** | `{"type":"message","model":"claude-...","usage":{"input_tokens":..., "output_tokens":..., "cache_read_input_tokens":..., "cache_creation_input_tokens":...}}` |
| **OpenAI** | `{"object":"chat.completion","model":"gpt-...","usage":{"prompt_tokens":..., "completion_tokens":...}}` and the newer `response` object |
| **Google Gemini** | `{"modelVersion":"gemini-...","usageMetadata":{"promptTokenCount":..., "candidatesTokenCount":..., "cachedContentTokenCount":...}}` |

Each line in your JSONL is expected to be a full API response. The parser is lenient: unparseable lines are skipped silently so you can point it at noisy log files.

## CLI

```bash
# Point at a file
llm-usage-report path/to/api-responses.jsonl

# Or a directory (scans recursively for *.jsonl)
llm-usage-report ./logs/

# Or pipe from stdin
tail -f logs/api.jsonl | llm-usage-report -

# Group by day, provider, project, or user
llm-usage-report logs/ --group-by day
llm-usage-report logs/ --group-by provider

# Machine-readable output
llm-usage-report logs/ --format json > report.json
llm-usage-report logs/ --format csv > report.csv
```

## Tagging requests with project / user

Include optional `project` and `user` fields at the top level of each log line:

```json
{"type":"message","model":"claude-sonnet-4-5","usage":{"input_tokens":100,"output_tokens":50},"project":"search","user":"alice"}
```

Then group by them:

```bash
llm-usage-report logs/ --group-by project
llm-usage-report logs/ --group-by user
```

## Pricing

Prices are embedded as a dated snapshot (see `src/llm_usage_report/pricing.py`). They will drift — provider prices change. Two ways to override:

```bash
# Via CLI flag
llm-usage-report logs/ --pricing ./my-pricing.json

# Or via environment variable
export LLM_USAGE_REPORT_PRICING=./my-pricing.json
llm-usage-report logs/
```

The override file has the same shape as the built-in table:

```json
{
  "claude-sonnet-4-5": {"input": 3.00, "output": 15.00, "cache_read": 0.30, "cache_creation": 3.75},
  "gpt-5": {"input": 15.00, "output": 60.00}
}
```

Rates are USD per **1 million tokens**. Unknown models contribute zero cost (token totals still aggregate correctly).

## Library API

```python
from llm_usage_report import parse_stream, aggregate, GroupKey
from llm_usage_report.formatters import format_table

with open("logs/api.jsonl") as f:
    records = list(parse_stream(f))

summaries = aggregate(records, group_by=GroupKey.MODEL)
print(format_table(summaries, group_label="model"))
```

## Philosophy

This package does one thing: it reads logs you already have and tells you what they cost. It does **not**:

- proxy your API calls (use LiteLLM if you want that)
- require adopting an SDK (use Braintrust / Helicone / LangSmith if you want full observability)
- pretend to know the future (pricing is a snapshot; override it when you need to)

If you outgrow this, good — that's what full LLM observability platforms are for. This is for the team that's logging to a file today and needs an answer before end of sprint.

## License

MIT.
