Metadata-Version: 2.4
Name: fluxmeter
Version: 1.1.0
Summary: Python SDK for FluxMeter — streaming metering for AI token billing
Project-URL: Homepage, https://github.com/10kshuaizhang/fluxmeter
Project-URL: Repository, https://github.com/10kshuaizhang/fluxmeter
Author-email: FluxMeter <hello@fluxmeter.dev>
License-Expression: Apache-2.0
Keywords: ai,anthropic,billing,llm,metering,openai,streaming,tokens
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.9
Requires-Dist: confluent-kafka>=2.3.0
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.20; extra == 'anthropic'
Provides-Extra: dev
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: pytest-asyncio; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Provides-Extra: openai
Requires-Dist: openai>=1.0; extra == 'openai'
Description-Content-Type: text/markdown

# FluxMeter Python SDK

Send AI token usage events to FluxMeter for real-time aggregation and billing.

## Install

```bash
pip install fluxmeter
```

## Quick Start — Lite mode (default, no Kafka)

```python
from fluxmeter import FluxMeter

meter = FluxMeter(api_url="http://localhost:8000")  # default
meter.track("cust_123", "gpt-4o", input_tokens=500, output_tokens=150)
```

Runs against `make demo` (API → Redis). Lite `/ingest` returns `cost_usd` and `balance_usd` in the response.

## Full stack (Kafka → Flink)

```python
meter = FluxMeter(kafka_brokers="localhost:9094", wal_enabled=True)
meter.track("cust_123", "gpt-4o", input_tokens=500, output_tokens=150)
```

## OpenAI Integration

```python
import time
from openai import OpenAI
from fluxmeter import FluxMeter

client = OpenAI()
meter = FluxMeter(api_url="http://localhost:8000", environment="production")

start = time.time()
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello!"}],
)
latency = int((time.time() - start) * 1000)

meter.track_openai("cust_123", response, latency_ms=latency)
```

## Anthropic Integration

```python
import anthropic
from fluxmeter import FluxMeter

client = anthropic.Anthropic()
meter = FluxMeter(api_url="http://localhost:8000")

response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello!"}],
)

meter.track_anthropic("cust_123", response)
```

## Multi-tenant (SaaS)

```python
meter.track(
    customer_id="cust_123",
    model_id="gpt-4o",
    tenant_id="tenant_acme",
    input_tokens=100,
    output_tokens=50,
)
```

Use with Flink full mode and `tenantId` on events for Redis key isolation.

## Manual Tracking (any provider)

```python
meter.track(
    customer_id="cust_123",
    model_id="gemini-1.5-pro",
    provider="google",
    input_tokens=2000,
    output_tokens=500,
    request_id="req_abc123",
    span_id="span_7f3a",
    session_id="sess_456",
    latency_ms=890,
    environment="production",
    metadata={"feature": "code-review", "team": "platform"},
)
```

## Configuration

```python
# HTTP (lite) with API key
meter = FluxMeter(
    api_url="https://meter.example.com",
    api_key="fm_live_...",
)

# Kafka (full) with WAL and SASL
meter = FluxMeter(
    kafka_brokers="kafka1:9092,kafka2:9092",
    topic="token-events",
    environment="production",
    wal_enabled=True,
    wal_path="~/.fluxmeter/wal",
    producer_config={
        "security.protocol": "SASL_SSL",
        "sasl.mechanisms": "PLAIN",
        "sasl.username": "...",
        "sasl.password": "...",
    },
)
```

| Parameter | Default | Description |
|-----------|---------|-------------|
| `api_url` | `http://localhost:8000` | HTTP ingest base URL (used when `kafka_brokers` is omitted) |
| `kafka_brokers` | `None` | If set, sends to Kafka instead of HTTP |
| `api_key` | `None` | `X-API-Key` header for HTTP ingest |

## How It Works

**Lite:**
```
Your App  →  meter.track(...)  →  POST /ingest  →  Redis (atomic Lua)
```

**Full:**
```
Your App  →  meter.track(...)  →  Kafka  →  Flink  →  Redis  →  API / Grafana
```

Kafka mode batches with lz4 compression and optional WAL for zero data loss during broker outages.

## Requirements

- Python 3.9+
- `confluent-kafka` (required for Kafka mode; installed with package)
- FluxMeter API running (`make demo`) or full stack (`make demo-full`)

## Release

See [docs/pypi-release.md](../../docs/pypi-release.md).
