Metadata-Version: 2.4
Name: trackyourapi
Version: 0.3.0
Summary: Official Python SDK for TrackYourAPI — AI API usage tracking
Author: TrackYourAPI
License: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Provides-Extra: openai
Requires-Dist: openai>=1.0.0; extra == "openai"
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.20.0; extra == "anthropic"
Provides-Extra: gemini
Requires-Dist: google-generativeai>=0.3.0; extra == "gemini"
Provides-Extra: genai
Requires-Dist: google-genai>=1.0.0; extra == "genai"
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.2.0; extra == "langchain"
Dynamic: author
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: license
Dynamic: provides-extra
Dynamic: requires-python
Dynamic: summary

# trackyourapi

> Official Python SDK for [TrackYourAPI](https://github.com/yashgaur01/TrackYourAPI): LLM cost, usage, latency and error tracking.

Wrap your OpenAI, Anthropic or Gemini client once. Every call is tracked, including **streaming responses**, **async clients** and **failed requests**. Standard library only, no hard dependencies.

## Installation

```bash
pip install trackyourapi
```

## Quick start

1. Sign in to your TrackYourAPI dashboard, open **API Keys**, and generate a key (`qt_...`). It is shown once.
2. Your `endpoint` is your TrackYourAPI Supabase project URL, e.g. `https://xxxx.supabase.co`.

### OpenAI (and OpenAI-compatible APIs)

```python
from openai import OpenAI
from trackyourapi import wrap_openai

client = wrap_openai(OpenAI(), api_key="qt_...", endpoint="https://YOUR-PROJECT.supabase.co")

# Regular and streaming calls are both tracked
response = client.chat.completions.create(model="gpt-4o", messages=[...])

for chunk in client.chat.completions.create(model="gpt-4o", messages=[...], stream=True):
    print(chunk.choices[0].delta.content or "", end="")
```

`AsyncOpenAI` works the same way. For DeepSeek, Groq, Mistral, OpenRouter or Ollama pass `provider="deepseek"` etc. so events are labelled correctly.

### Anthropic

```python
from anthropic import Anthropic
from trackyourapi import wrap_anthropic

client = wrap_anthropic(Anthropic(), api_key="qt_...", endpoint="https://YOUR-PROJECT.supabase.co")
msg = client.messages.create(model="claude-sonnet-4-0", max_tokens=1024, messages=[...])
# stream=True is tracked too. (The messages.stream() helper is not intercepted yet.)
```

### Google Gemini

```python
import google.generativeai as genai
from trackyourapi import wrap_gemini

genai.configure(api_key="...")
model = wrap_gemini(genai.GenerativeModel("gemini-2.0-flash"),
                    api_key="qt_...", endpoint="https://YOUR-PROJECT.supabase.co")
response = model.generate_content("Hello!")
```

## Also supported

- **Google GenAI (`google-genai`)**: `wrap_genai(genai.Client(), ...)` tracks `models.generate_content`, `generate_content_stream` and the `aio` async variants.
- **OpenAI Responses API**: `responses.create` is tracked when present, including streaming.
- **Anthropic `messages.stream()`** context manager is tracked when the block exits.
- **LangChain**: `from trackyourapi.integrations.langchain import TrackYourAPICallbackHandler` and pass it in `callbacks=[...]`.

## Prompt and response capture

Off by default. Pass `capture_content=True` to send prompt and completion text with each event. The server only stores it when the project has **content capture** enabled in Settings, truncated to the project's limit.

## Cost attribution with metadata

```python
# Applied to every event from this client
client = wrap_openai(OpenAI(), api_key=..., endpoint=..., metadata={"environment": "production"})

# Per call: the extra kwarg is stripped before the request is sent
client.chat.completions.create(model="gpt-4o", messages=[...],
                               trackyourapi={"customer_id": "acme", "feature": "summarize"})
```

## What gets tracked

| Field | Description |
|---|---|
| `provider`, `model` | Provider label and the exact model the API reported |
| `prompt_tokens`, `completion_tokens` | Real split from the provider (cached prompt tokens count as input) |
| `latency` | Request duration in ms. For streams, time until the stream finished |
| `status`, `error_message` | `error` when the call raised (rate limits, timeouts, bad requests) |
| `metadata` | Your tags, merged from client and per-call metadata |

**Cost is computed server-side** from TrackYourAPI's pricing table. For custom providers the server does not know, send `cost` yourself via manual tracking.

## Manual tracking (any provider)

```python
from trackyourapi import TrackYourAPIClient

tracker = TrackYourAPIClient(api_key="qt_...", endpoint="https://YOUR-PROJECT.supabase.co")
tracker.track(provider="mistral", model="mistral-large",
              prompt_tokens=1200, completion_tokens=300, cost=0.004, latency=320,
              metadata={"customer_id": "acme"})
```

Events are sent from a background thread and flushed automatically at exit. Call `tracker.flush()` in short-lived scripts if you want to be sure. `debug=True` prints delivery failures.

## License

MIT
