Metadata-Version: 2.4
Name: carbonwatcher
Version: 0.2.0
Summary: Track energy, carbon, and cost of ML experiments and LLM API calls — CLI and Python module with automatic token counting.
Home-page: https://github.com/ghanshyampaunikar/carbonwatcher
Author: Ghanshyam Paunikar
Author-email: ghanshyampaunikar@gmail.com
License: MIT
Project-URL: Bug Reports, https://github.com/ghanshyampaunikar/carbonwatcher/issues
Project-URL: Source, https://github.com/ghanshyampaunikar/carbonwatcher
Keywords: carbon,emissions,energy,sustainability,machine-learning,llm,tracking,green-ai,co2,climate
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
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: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: System :: Monitoring
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: psutil>=5.9.0
Requires-Dist: nvidia-ml-py>=12.535.77
Requires-Dist: rich>=13.0.0
Requires-Dist: click>=8.1.0
Requires-Dist: requests>=2.31.0
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.25.0; extra == "anthropic"
Provides-Extra: openai
Requires-Dist: openai>=1.0.0; extra == "openai"
Provides-Extra: ollama
Requires-Dist: ollama>=0.2.0; extra == "ollama"
Provides-Extra: huggingface
Requires-Dist: transformers>=4.35.0; extra == "huggingface"
Requires-Dist: torch>=2.0.0; extra == "huggingface"
Provides-Extra: llamacpp
Requires-Dist: llama-cpp-python>=0.2.0; extra == "llamacpp"
Provides-Extra: tiktoken
Requires-Dist: tiktoken>=0.5.0; extra == "tiktoken"
Provides-Extra: all
Requires-Dist: anthropic>=0.25.0; extra == "all"
Requires-Dist: openai>=1.0.0; extra == "all"
Requires-Dist: ollama>=0.2.0; extra == "all"
Requires-Dist: transformers>=4.35.0; extra == "all"
Requires-Dist: torch>=2.0.0; extra == "all"
Requires-Dist: llama-cpp-python>=0.2.0; extra == "all"
Requires-Dist: tiktoken>=0.5.0; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: tiktoken>=0.5.0; extra == "dev"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: project-url
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# Carbon Trace

Track the energy, carbon, and cost of ML training runs and LLM API calls — automatically, with no changes to your existing code.

```
pip install carbonwatcher
```

## Why

Every GPU training job and every LLM API call burns electricity. The carbon footprint depends on **where** that electricity comes from. A model trained in Ireland emits 8× less CO₂ than the same job run in India. Most teams have no idea what their AI compute actually costs the planet.

Carbon Trace makes it automatic: wrap your training loop or your API client, and it logs energy, carbon, and cost to a ledger you can query and share.

---

## Quick start

### Wrap a training script (no code changes)

```bash
carbonwatcher run python train.py
carbonwatcher run --region eu-west-1 --log-dir ./logs -- python train.py
```

### Context manager

```python
from carbon_trace import CarbonTracker

with CarbonTracker(experiment_name="resnet50", model_name="ResNet50") as ct:
    train(...)

# prints summary automatically
```

### Epoch-based API (recommended for long runs)

```python
from carbon_trace import CarbonTracker

tracker = CarbonTracker(epochs=100, monitor_epochs=2, experiment_name="bert-ft")
for epoch in range(100):
    tracker.epoch_start()
    train_one_epoch(...)
    tracker.epoch_end()   # prints per-epoch stats + prediction after epoch 2
tracker.stop()
```

After `monitor_epochs` epochs it extrapolates and prints:

```
  [Predicted for 100 epochs]
    Time:    01:24:00
    Energy:  840.0000 Wh
    Carbon:  168.0000 gCO2e
```

### Decorator

```python
from carbon_trace import CarbonTracker

@CarbonTracker.track(experiment="gpt2-finetune", model="GPT-2")
def train():
    ...
```

---

## LLM token tracking

Track carbon and cost of LLM API calls — token counts come from the API response, no manual counting needed.

### Anthropic / Claude

```python
from carbon_trace.llm.anthropic_wrapper import TrackedAnthropic

client = TrackedAnthropic()   # drop-in for anthropic.Anthropic()

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Explain transformers."}],
)
# carbon + cost logged automatically
```

### OpenAI

```python
from carbon_trace.llm.openai_wrapper import TrackedOpenAI

client = TrackedOpenAI()   # drop-in for openai.OpenAI()

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello"}],
)
```

### Ollama (local)

```python
from carbon_trace.llm.ollama_wrapper import TrackedOllama

client = TrackedOllama()   # drop-in for ollama.Client()
response = client.chat(model="llama3.2", messages=[{"role": "user", "content": "Hi"}])
```

### HuggingFace (local)

```python
from carbon_trace.llm.huggingface_wrapper import TrackedHuggingFace

model = TrackedHuggingFace("gpt2")
output = model.generate("Once upon a time")
```

### llama.cpp (local)

```python
from carbon_trace.llm.llamacpp_wrapper import TrackedLlamaCpp

llm = TrackedLlamaCpp("models/llama-3.2-3b.gguf")
response = llm.chat([{"role": "user", "content": "Hello"}])
```

---

## CLI reference

```
carbonwatcher --help
```

| Command | Description |
|---------|-------------|
| `run`            | Wrap any script — `carbonwatcher run python train.py` |
| `runs`           | List all recorded training runs |
| `compare`        | Rank runs by carbon efficiency |
| `estimate`       | Quick carbon estimate for energy + region |
| `regions`        | Compare carbon intensity across all regions |
| `config`         | Set your region, name, and organization |
| `dashboard`      | Monthly emissions with ASCII bar charts |
| `goals set`      | Set monthly/yearly carbon targets |
| `goals progress` | Show progress toward your targets |
| `team`           | Compare carbon across team members |
| `llm-runs`       | List all LLM API calls |
| `llm-estimate`   | Estimate carbon for one LLM call |
| `llm-compare`    | Rank all known models by carbon footprint |
| `llm-models`     | List all supported models |
| `logs`           | Parse structured log files |

### Config

```bash
# Set your location and identity once
carbonwatcher config --region India --user-name Alice --organization Acme

# Show current config
carbonwatcher config --show
```

### Dashboard

```bash
carbonwatcher dashboard
carbonwatcher dashboard --export-json report.json
carbonwatcher dashboard --export-csv report.csv
```

### Goals

```bash
# Set a monthly carbon budget of 500 gCO2e and $5 cost cap
carbonwatcher goals set --monthly 500 --cost-monthly 5.0

# Set a yearly budget
carbonwatcher goals set --yearly 5000

# Check progress
carbonwatcher goals progress
```

### Team reports

```bash
# Compare team members (each person has their own ledger)
carbonwatcher team alice_ledger.json bob_ledger.json carol_ledger.json

# Filter by month
carbonwatcher team *.json --month 2026-05

# Include LLM usage
carbonwatcher team alice_ledger.json --llm-ledger alice_llm_ledger.json
```

---

## Location-aware carbon

Carbon Trace automatically detects your location and uses the local grid's carbon intensity.

| Region | Intensity |
|--------|-----------|
| Norway | 28 gCO2/kWh |
| France | 58 gCO2/kWh |
| Ireland (EU West) | 88 gCO2/kWh |
| California | 220 gCO2/kWh |
| USA average | 386 gCO2/kWh |
| India | 708 gCO2/kWh |
| Australia | 790 gCO2/kWh |

For LLM API calls, the **server's** grid is used, not yours:
- Anthropic (Claude): ~200 gCO2/kWh (AWS + GCP blended)
- OpenAI: ~200 gCO2/kWh
- Mistral AI: 58 gCO2/kWh (French grid)

---

## Python module API

```python
from carbon_trace import CarbonTracker
from carbon_trace.llm.tracker import LLMTracker
from carbon_trace.dashboard.monthly import combined_monthly, print_monthly_dashboard
from carbon_trace.dashboard.goals import set_goal, print_goals_progress
from carbon_trace.team.report import print_team_report
from carbon_trace.parser import parse_all_logs, aggregate_logs

# Monthly dashboard data
data = combined_monthly("ledger.json", "llm_ledger.json")

# Team stats
print_team_report(["alice.json", "bob.json"], month="2026-05")

# Parse log files
logs = parse_all_logs("./logs", experiment="bert-ft")
agg  = aggregate_logs(logs)
```

---

## Installation

```bash
# Core (training tracking + CLI)
pip install carbonwatcher

# With Claude/Anthropic support
pip install "carbonwatcher[anthropic]"

# With OpenAI support
pip install "carbonwatcher[openai]"

# With local model support (Ollama + HuggingFace + llama.cpp)
pip install "carbonwatcher[ollama,huggingface,llamacpp]"

# Everything
pip install "carbonwatcher[all]"
```

### Requirements

- Python 3.9+
- macOS, Linux (Windows: CPU power estimated via TDP, no RAPL)

### Hardware power measurement

| Platform | Method |
|----------|--------|
| Intel CPU (Linux) | RAPL — direct energy counter, exact |
| Apple Silicon (macOS) | `powermetrics` — accurate but needs `sudo` for real-time; falls back to TDP estimate |
| NVIDIA GPU | NVML — direct power sensor |
| Other | TDP-based estimate (conservative) |

---

## Output example

```
Run:        a3f2c1b8
Experiment: bert-finetune  |  Model: bert-base-uncased
CPU:        Apple M1  [tdp_estimate]
GPU:        None detected
Duration:   142.3s
Energy:     3.1200 Wh  (CPU: 2.8400  GPU: 0.0000  DRAM: 0.0560)  PUE×1.10
Carbon:     2.209 gCO2e  (0.00000221 kg)
Grid:       India @ 708.0 gCO2/kWh  [static_table]
Cost:       $0.0312 USD
Equiv:      0.0002 phone charges  |  0.000014 km driven
```

---

## License

MIT
