ai-footprint
v0.1.0
Published
Deterministic CO2 and energy impact calculator for AI inference calls
Maintainers
Readme
Why ai-footprint?
Most libraries rely on opaque vendor estimates. ai-footprint is intentionally input‑driven: you provide measurable facts (power draw, parameters, region, throughput), and it returns a deterministic estimate.
Use cases
- Carbon reporting and sustainability dashboards
- Comparing model configurations and batch sizes
- Batch/weekly/monthly footprint reporting
- Research or internal cost/impact analysis
Table of Contents
- Features
- Install
- Quickstart
- Core Concepts
- Model Categories
- Regions, Aliases, and Fallbacks
- Examples
- Batch Aggregation
- Uncertainty Ranges
- Notes and Best Practices
- Data Source
- License
Features
- Deterministic, input‑driven estimation
- Model‑type specific usage metrics (tokens, audio seconds, pixels, images)
- Returns kWh and grams of CO2
- TypeScript‑first API
- Extensible categories and region grid‑intensity mapping
- Optional advanced inputs (measured time, PUE, power breakdown, quantization metadata)
- Batch aggregation for weekly/monthly totals
- Uncertainty ranges for min/max emissions
Install
npm install ai-footprintQuickstart
import { estimateImpact, usage } from "ai-footprint";
const result = estimateImpact({
gpuPowerW: 350,
modelParamsB: 70,
region: "eu",
usage: usage.chat(1200, 400),
throughput: {
tokensPerSecond: 90
}
});
console.log(result.energyKwh, result.co2Grams);Core Concepts
What you provide
- Hardware: GPU power draw in watts (average during inference)
- Model: parameter count (e.g., 7B, 70B)
- Region: location or explicit grid carbon intensity (gCO2/kWh)
- Workload metrics: based on model type (tokens, seconds, pixels, etc.)
What you get
- Energy (kWh) used by the request
- Emissions (gCO2) for the energy used
Model Categories
The library uses categories aligned with common API types:
chat.completions— input + output tokenstext.completions— input + output tokensembeddings— input tokens onlyocr— input + output tokensaudio.transcription— seconds of audio processedaudio.translation— seconds of audio processedaudio.speech— seconds of audio generatedimage.generation— pixels + number of images
Regions, Aliases, and Fallbacks
The library accepts a region string and normalizes it. If a region is not recognized, it falls back to the global average and prints a warning in the console.
Supported base regions with per‑country values
global,eu,us,ukfr,de,it,es,nl,se,no,fi,ca,jp,sg,au,in,brat,be,ba,bg,hr,cy,cz,dk,ee,gr,hu,ie,xk,lv,lt,lu,mt,me,mk,pl,pt,ro,rs,sk,si,ch,tr
Common aliases (normalized)
gb,united kingdom→ukusa,us-east,us-west,us-central→useu-west,eu-central,europe,eu (ember)→eu
Name‑based aliases from the dataset
czechia→czswitzerland→chturkey→trkosovo→xknorth macedonia→mkmontenegro→meserbia→rsbosnia and herzegovina→ba
Additional country codes (mapped to global)
ae,ar,bd,cl,cn,co,dz,eg,hk,id,il,ke,kr,ma,mx,my,ng,nz,pe,ph,pk,sa,th,tw,vn,za
If you want exact local values, pass gridCarbonIntensityGPerKwh directly.
Examples
Minimal: embeddings
import { estimateImpact, usage } from "ai-footprint";
const result = estimateImpact({
gpuPowerW: 250,
modelParamsB: 7,
region: "us",
usage: usage.embeddings(1800),
throughput: { tokensPerSecond: 300 }
});Minimal: audio transcription
import { estimateImpact, usage } from "ai-footprint";
const result = estimateImpact({
gpuPowerW: 300,
modelParamsB: 1.5,
region: "uk",
usage: usage.audioTranscription(120),
throughput: { audioSecondsPerSecond: 0.5 }
});Minimal: image generation
import { estimateImpact, usage } from "ai-footprint";
const result = estimateImpact({
gpuPowerW: 320,
modelParamsB: 20,
region: "de",
usage: usage.imageGeneration(1024, 1024, 2),
throughput: { pixelsPerSecond: 120000 }
});Measured latency (processing time overrides derived time)
import { estimateImpact, usage } from "ai-footprint";
const result = estimateImpact({
gpuPowerW: 400,
modelParamsB: 70,
region: "us",
processingTimeSeconds: 1.84,
usage: usage.chat(1200, 400)
});PUE (data center overhead)
import { estimateImpact, usage } from "ai-footprint";
const result = estimateImpact({
gpuPowerW: 350,
modelParamsB: 70,
region: "eu",
overheadFactor: 1.2, // use this as PUE if preferred
usage: usage.chat(1200, 400),
throughput: { tokensPerSecond: 90 }
});Power breakdown (GPU + CPU + network)
import { estimateImpact, usage } from "ai-footprint";
const gpuPowerW = 300;
const cpuPowerW = 60;
const networkPowerW = 15;
const result = estimateImpact({
gpuPowerW: gpuPowerW + cpuPowerW + networkPowerW,
modelParamsB: 13,
region: "fr",
usage: usage.chat(800, 200),
throughput: { tokensPerSecond: 120 }
});Dynamic grid intensity
import { estimateImpact, usage } from "ai-footprint";
const result = estimateImpact({
gpuPowerW: 350,
modelParamsB: 70,
gridCarbonIntensityGPerKwh: 210,
usage: usage.chat(1200, 400),
throughput: { tokensPerSecond: 90 }
});Quantization, batch size, and efficiency factors
import { estimateImpact, usage } from "ai-footprint";
const result = estimateImpact({
gpuPowerW: 220,
modelParamsB: 70,
region: "eu",
usage: usage.chat(2000, 400),
throughput: { tokensPerSecond: 240 }
});Batch Aggregation
import { aggregateImpacts, estimateImpact, usage } from "ai-footprint";
const impacts = [
estimateImpact({
gpuPowerW: 350,
modelParamsB: 70,
region: "eu",
usage: usage.chat(1200, 400),
throughput: { tokensPerSecond: 90 }
}),
estimateImpact({
gpuPowerW: 250,
modelParamsB: 7,
region: "us",
usage: usage.embeddings(1800),
throughput: { tokensPerSecond: 300 }
})
];
const total = aggregateImpacts(impacts);
console.log(total.count, total.energyKwh, total.co2Grams);Uncertainty Ranges
import { estimateImpactRange, usage } from "ai-footprint";
const result = estimateImpactRange(
{
gpuPowerW: 350,
modelParamsB: 70,
region: "eu",
usage: usage.chat(1200, 400),
throughput: { tokensPerSecond: 90 }
},
{
gpuPowerW: { min: 300, max: 420 },
pue: { min: 1.1, max: 1.4 },
tokensPerSecond: { min: 70, max: 110 }
}
);
console.log(result.energyKwhMin, result.energyKwhMax);
console.log(result.co2GramsMin, result.co2GramsMax);Notes and Best Practices
- Use measured
processingTimeSecondswhen available. - Prefer explicit
gridCarbonIntensityGPerKwhif you can fetch it from a live data source. - If you don’t know throughput, you can still get a minimal estimate by assuming a conservative value.
- If you pass an unknown
region, the library will warn in console and fall back toglobal.
Data Source
The per‑country dataset is decoupled in src/data/grid-carbon-intensity.2025.json (year 2025).
Source: Our World in Data — https://ourworldindata.org/grapher/carbon-intensity-electricity
License
MIT
