llm-tracker 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ # Copy this file to .env and fill in your values.
2
+
3
+ # ── Who you are (used for cost attribution) ──
4
+ LLM_TRACKER_API_NAME=snapshot # Your service/repo name
5
+ LLM_TRACKER_USER_ID=your-user-id # Your personal/team ID
6
+
7
+ # ── MySQL connection ──
8
+ LLM_TRACKER_DB_HOST=localhost
9
+ LLM_TRACKER_DB_PORT=3306
10
+ LLM_TRACKER_DB_USER=root
11
+ LLM_TRACKER_DB_PASSWORD=
12
+ LLM_TRACKER_DB_NAME=oneclarity_db
13
+
14
+ # ── Optional ──
15
+ LLM_TRACKER_USE_SSL=1 # Enable SSL for managed MySQL (0=off, 1=on, default: 1)
16
+ LLM_TRACKER_SSL_CA= # Path to CA certificate, if required by your provider
17
+ LLM_TRACKER_DEFAULT_ENV=test # Environment label: test/beta/prod (default: test)
18
+ LLM_TRACKER_PRICING_JSON= # Override the built-in pricing table as JSON, e.g.
19
+ # {"gpt-4o-mini":{"input":0.00015,"output":0.0006}}
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OneClarity
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,5 @@
1
+ include README.md
2
+ include LICENSE
3
+ include schema.sql
4
+ include .env.example
5
+ include requirements.txt
@@ -0,0 +1,254 @@
1
+ Metadata-Version: 2.4
2
+ Name: llm-tracker
3
+ Version: 0.2.0
4
+ Summary: Track LLM API costs, tokens, and latency to MySQL
5
+ Author-email: OneClarity <dev@oneclarity.ai>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/mentor-oneclarity/AI_LLM_Tracking
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: openai>=1.30.0
18
+ Requires-Dist: sqlalchemy>=2.0.0
19
+ Requires-Dist: pymysql>=1.1.0
20
+ Requires-Dist: python-dotenv>=1.0.0
21
+ Requires-Dist: starlette>=0.37.0
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest>=7.0; extra == "dev"
24
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
25
+ Requires-Dist: black>=22.0; extra == "dev"
26
+ Requires-Dist: flake8>=4.0; extra == "dev"
27
+ Dynamic: license-file
28
+
29
+ # llm_tracker
30
+
31
+ Automatically log OpenAI API usage (tokens, cost, latency) to MySQL. Drop-in wrapper that requires only a 1-line import change.
32
+
33
+ ## What It Does
34
+
35
+ Every call to `client.chat.completions.create()` logs:
36
+ - **Tokens** (prompt, completion, total)
37
+ - **Cost** (calculated from pricing table)
38
+ - **Latency** (milliseconds)
39
+ - **Metadata** (service name, endpoint, environment, user ID, request ID)
40
+
41
+ All logged to MySQL table `ai_llm_usage_logs` for cost analysis dashboards.
42
+
43
+ ---
44
+
45
+ ## Quick Start (5 minutes)
46
+
47
+ ### 1. Install
48
+
49
+ ```bash
50
+ pip install llm-tracker
51
+ ```
52
+
53
+ ### 2. Configure
54
+
55
+ Copy `.env.example` to `.env` and fill in:
56
+
57
+ ```bash
58
+ # Who you are
59
+ LLM_TRACKER_API_NAME=snapshot # Your service name
60
+ LLM_TRACKER_USER_ID=your-user-id # Your personal/team ID
61
+
62
+ # MySQL connection
63
+ LLM_TRACKER_DB_HOST=mysql.example.com
64
+ LLM_TRACKER_DB_PORT=3306
65
+ LLM_TRACKER_DB_USER=mysqladmin
66
+ LLM_TRACKER_DB_PASSWORD=password
67
+ LLM_TRACKER_DB_NAME=dev_db
68
+
69
+ # Optional
70
+ LLM_TRACKER_USE_SSL=1 # SSL enabled (default: 1)
71
+ LLM_TRACKER_DEFAULT_ENV=beta # test/beta/prod (default: test)
72
+ ```
73
+
74
+ See `.env.example` for all variables with explanations.
75
+
76
+ ### 3. Initialize Database
77
+
78
+ **First time only:**
79
+ ```bash
80
+ python -c "from llm_tracker.db import init_db; init_db()"
81
+ ```
82
+
83
+ This creates the `ai_llm_usage_logs` table.
84
+
85
+ ### 4. Use Tracked Client
86
+
87
+ **In your code**, change only the import:
88
+
89
+ ```python
90
+ # Before
91
+ from openai import OpenAI
92
+ client = OpenAI(api_key="...", base_url="...")
93
+
94
+ # After
95
+ from llm_tracker import TrackedOpenAI
96
+ client = TrackedOpenAI(api_key="...", base_url="...")
97
+
98
+ # Everything else stays the same
99
+ response = client.chat.completions.create(
100
+ model="gpt-4o",
101
+ messages=[{"role": "user", "content": "hello"}]
102
+ )
103
+ ```
104
+
105
+ ### 5. (FastAPI only) Add Middleware
106
+
107
+ In your FastAPI app startup:
108
+
109
+ ```python
110
+ from fastapi import FastAPI
111
+ from llm_tracker.middleware import LLMContextMiddleware
112
+
113
+ app = FastAPI()
114
+ app.add_middleware(LLMContextMiddleware)
115
+ ```
116
+
117
+ This automatically populates:
118
+ - `api_name` — your service name (from env)
119
+ - `endpoint` — the route path (e.g., `/jobs/medium-brain`)
120
+ - `user_id` — your ID (from env)
121
+ - `request_id` — unique per request (auto-generated)
122
+ - `environment` — from env var or `X-Env` header
123
+
124
+ ---
125
+
126
+ ## Environment Variables
127
+
128
+ ### Required
129
+
130
+ | Variable | Example | Description |
131
+ |----------|---------|-------------|
132
+ | `LLM_TRACKER_API_NAME` | `snapshot` | Your service/repo name |
133
+ | `LLM_TRACKER_USER_ID` | `abc123def` | Your personal/team ID (cost attribution) |
134
+ | `LLM_TRACKER_DB_HOST` | `mysql.example.com` | MySQL hostname |
135
+ | `LLM_TRACKER_DB_USER` | `mysqladmin` | MySQL username |
136
+ | `LLM_TRACKER_DB_PASSWORD` | `password123` | MySQL password |
137
+ | `LLM_TRACKER_DB_NAME` | `dev_db` | MySQL database name |
138
+
139
+ ### Optional
140
+
141
+ | Variable | Default | Description |
142
+ |----------|---------|-------------|
143
+ | `LLM_TRACKER_DB_PORT` | `3306` | MySQL port |
144
+ | `LLM_TRACKER_USE_SSL` | `1` | Enable SSL (0=off, 1=on) |
145
+ | `LLM_TRACKER_SSL_CA` | (system) | Path to CA certificate |
146
+ | `LLM_TRACKER_DEFAULT_ENV` | `test` | Environment label: `test`, `beta`, or `prod` |
147
+ | `LLM_TRACKER_PRICING_JSON` | (built-in) | Override pricing table as JSON |
148
+
149
+ ### Special: Per-Request Environment
150
+
151
+ Send `X-Env` header to override environment for a single request:
152
+
153
+ ```bash
154
+ curl -H "X-Env: test" http://localhost:8088/jobs/medium-brain
155
+ ```
156
+
157
+ ---
158
+
159
+ ## What Gets Logged
160
+
161
+ Table: `ai_llm_usage_logs`
162
+
163
+ | Column | Example | Notes |
164
+ |--------|---------|-------|
165
+ | `id` | `a1b2c3d4-...` | UUID (auto-generated) |
166
+ | `created_at` | `2026-07-07 12:30:45` | IST timestamp (auto) |
167
+ | `api_name` | `snapshot` | From `LLM_TRACKER_API_NAME` |
168
+ | `endpoint` | `/jobs/medium-brain` | HTTP route (FastAPI only) |
169
+ | `deployment` | `gpt-4o` | Model name |
170
+ | `environment` | `beta` | From `LLM_TRACKER_DEFAULT_ENV` |
171
+ | `user_id` | `abc123def` | From `LLM_TRACKER_USER_ID` |
172
+ | `request_id` | `xyz789abc` | Per-request UUID (FastAPI) |
173
+ | `prompt_tokens` | `150` | Input tokens |
174
+ | `completion_tokens` | `50` | Output tokens |
175
+ | `total_tokens` | `200` | Sum |
176
+ | `cost_usd` | `0.0045` | Calculated cost |
177
+ | `latency_ms` | `1234` | Round-trip time |
178
+
179
+ ### Query Example
180
+
181
+ ```sql
182
+ -- Total cost by endpoint (last 7 days)
183
+ SELECT endpoint, deployment, COUNT(*) as calls, SUM(cost_usd) as total_cost
184
+ FROM ai_llm_usage_logs
185
+ WHERE api_name = 'snapshot' AND created_at > NOW() - INTERVAL 7 DAY
186
+ GROUP BY endpoint, deployment
187
+ ORDER BY total_cost DESC;
188
+ ```
189
+
190
+ ---
191
+
192
+ ## For Manual Scripts (No FastAPI)
193
+
194
+ Load env vars and call `flush()` before exit:
195
+
196
+ ```python
197
+ from dotenv import load_dotenv
198
+ from llm_tracker import TrackedOpenAI
199
+ from llm_tracker.logger import flush
200
+
201
+ load_dotenv()
202
+
203
+ client = TrackedOpenAI(api_key="...")
204
+ response = client.chat.completions.create(
205
+ model="gpt-4o",
206
+ messages=[...]
207
+ )
208
+
209
+ flush() # ensure background writes finish before script exits
210
+ ```
211
+
212
+ ---
213
+
214
+ ## Supported Models
215
+
216
+ Built-in pricing for:
217
+ - `gpt-4o` — $0.0025 input / $0.01 output per 1K tokens
218
+ - `gpt-4o-mini` — $0.00015 input / $0.0006 output per 1K tokens
219
+ - `gpt-4.1` — $0.002 input / $0.008 output per 1K tokens
220
+
221
+ Unknown models log `$0.00` cost. Override pricing with `LLM_TRACKER_PRICING_JSON`.
222
+
223
+ ---
224
+
225
+ ## Async Support
226
+
227
+ For async apps, use `TrackedAsyncOpenAI` / `TrackedAsyncAzureOpenAI` — same API, `await` the call:
228
+
229
+ ```python
230
+ from llm_tracker import TrackedAsyncOpenAI
231
+ from llm_tracker.logger import aflush
232
+
233
+ client = TrackedAsyncOpenAI(api_key="...")
234
+ response = await client.chat.completions.create(
235
+ model="gpt-4o",
236
+ messages=[{"role": "user", "content": "hello"}],
237
+ )
238
+
239
+ await aflush() # async-friendly equivalent of flush()
240
+ ```
241
+
242
+ ## Known Limitations
243
+
244
+ - ❌ Streaming (`stream=True`) not supported
245
+ - ❌ Embeddings not tracked (by design — cheap)
246
+ - ✓ Sync and async OpenAI/AzureOpenAI clients supported
247
+
248
+ ---
249
+
250
+ ## Support
251
+
252
+ - **Issues**: GitHub issues
253
+ - **Docs**: See `.env.example` and `schema.sql`
254
+ - **Examples**: `example_usage.py`
@@ -0,0 +1,226 @@
1
+ # llm_tracker
2
+
3
+ Automatically log OpenAI API usage (tokens, cost, latency) to MySQL. Drop-in wrapper that requires only a 1-line import change.
4
+
5
+ ## What It Does
6
+
7
+ Every call to `client.chat.completions.create()` logs:
8
+ - **Tokens** (prompt, completion, total)
9
+ - **Cost** (calculated from pricing table)
10
+ - **Latency** (milliseconds)
11
+ - **Metadata** (service name, endpoint, environment, user ID, request ID)
12
+
13
+ All logged to MySQL table `ai_llm_usage_logs` for cost analysis dashboards.
14
+
15
+ ---
16
+
17
+ ## Quick Start (5 minutes)
18
+
19
+ ### 1. Install
20
+
21
+ ```bash
22
+ pip install llm-tracker
23
+ ```
24
+
25
+ ### 2. Configure
26
+
27
+ Copy `.env.example` to `.env` and fill in:
28
+
29
+ ```bash
30
+ # Who you are
31
+ LLM_TRACKER_API_NAME=snapshot # Your service name
32
+ LLM_TRACKER_USER_ID=your-user-id # Your personal/team ID
33
+
34
+ # MySQL connection
35
+ LLM_TRACKER_DB_HOST=mysql.example.com
36
+ LLM_TRACKER_DB_PORT=3306
37
+ LLM_TRACKER_DB_USER=mysqladmin
38
+ LLM_TRACKER_DB_PASSWORD=password
39
+ LLM_TRACKER_DB_NAME=dev_db
40
+
41
+ # Optional
42
+ LLM_TRACKER_USE_SSL=1 # SSL enabled (default: 1)
43
+ LLM_TRACKER_DEFAULT_ENV=beta # test/beta/prod (default: test)
44
+ ```
45
+
46
+ See `.env.example` for all variables with explanations.
47
+
48
+ ### 3. Initialize Database
49
+
50
+ **First time only:**
51
+ ```bash
52
+ python -c "from llm_tracker.db import init_db; init_db()"
53
+ ```
54
+
55
+ This creates the `ai_llm_usage_logs` table.
56
+
57
+ ### 4. Use Tracked Client
58
+
59
+ **In your code**, change only the import:
60
+
61
+ ```python
62
+ # Before
63
+ from openai import OpenAI
64
+ client = OpenAI(api_key="...", base_url="...")
65
+
66
+ # After
67
+ from llm_tracker import TrackedOpenAI
68
+ client = TrackedOpenAI(api_key="...", base_url="...")
69
+
70
+ # Everything else stays the same
71
+ response = client.chat.completions.create(
72
+ model="gpt-4o",
73
+ messages=[{"role": "user", "content": "hello"}]
74
+ )
75
+ ```
76
+
77
+ ### 5. (FastAPI only) Add Middleware
78
+
79
+ In your FastAPI app startup:
80
+
81
+ ```python
82
+ from fastapi import FastAPI
83
+ from llm_tracker.middleware import LLMContextMiddleware
84
+
85
+ app = FastAPI()
86
+ app.add_middleware(LLMContextMiddleware)
87
+ ```
88
+
89
+ This automatically populates:
90
+ - `api_name` — your service name (from env)
91
+ - `endpoint` — the route path (e.g., `/jobs/medium-brain`)
92
+ - `user_id` — your ID (from env)
93
+ - `request_id` — unique per request (auto-generated)
94
+ - `environment` — from env var or `X-Env` header
95
+
96
+ ---
97
+
98
+ ## Environment Variables
99
+
100
+ ### Required
101
+
102
+ | Variable | Example | Description |
103
+ |----------|---------|-------------|
104
+ | `LLM_TRACKER_API_NAME` | `snapshot` | Your service/repo name |
105
+ | `LLM_TRACKER_USER_ID` | `abc123def` | Your personal/team ID (cost attribution) |
106
+ | `LLM_TRACKER_DB_HOST` | `mysql.example.com` | MySQL hostname |
107
+ | `LLM_TRACKER_DB_USER` | `mysqladmin` | MySQL username |
108
+ | `LLM_TRACKER_DB_PASSWORD` | `password123` | MySQL password |
109
+ | `LLM_TRACKER_DB_NAME` | `dev_db` | MySQL database name |
110
+
111
+ ### Optional
112
+
113
+ | Variable | Default | Description |
114
+ |----------|---------|-------------|
115
+ | `LLM_TRACKER_DB_PORT` | `3306` | MySQL port |
116
+ | `LLM_TRACKER_USE_SSL` | `1` | Enable SSL (0=off, 1=on) |
117
+ | `LLM_TRACKER_SSL_CA` | (system) | Path to CA certificate |
118
+ | `LLM_TRACKER_DEFAULT_ENV` | `test` | Environment label: `test`, `beta`, or `prod` |
119
+ | `LLM_TRACKER_PRICING_JSON` | (built-in) | Override pricing table as JSON |
120
+
121
+ ### Special: Per-Request Environment
122
+
123
+ Send `X-Env` header to override environment for a single request:
124
+
125
+ ```bash
126
+ curl -H "X-Env: test" http://localhost:8088/jobs/medium-brain
127
+ ```
128
+
129
+ ---
130
+
131
+ ## What Gets Logged
132
+
133
+ Table: `ai_llm_usage_logs`
134
+
135
+ | Column | Example | Notes |
136
+ |--------|---------|-------|
137
+ | `id` | `a1b2c3d4-...` | UUID (auto-generated) |
138
+ | `created_at` | `2026-07-07 12:30:45` | IST timestamp (auto) |
139
+ | `api_name` | `snapshot` | From `LLM_TRACKER_API_NAME` |
140
+ | `endpoint` | `/jobs/medium-brain` | HTTP route (FastAPI only) |
141
+ | `deployment` | `gpt-4o` | Model name |
142
+ | `environment` | `beta` | From `LLM_TRACKER_DEFAULT_ENV` |
143
+ | `user_id` | `abc123def` | From `LLM_TRACKER_USER_ID` |
144
+ | `request_id` | `xyz789abc` | Per-request UUID (FastAPI) |
145
+ | `prompt_tokens` | `150` | Input tokens |
146
+ | `completion_tokens` | `50` | Output tokens |
147
+ | `total_tokens` | `200` | Sum |
148
+ | `cost_usd` | `0.0045` | Calculated cost |
149
+ | `latency_ms` | `1234` | Round-trip time |
150
+
151
+ ### Query Example
152
+
153
+ ```sql
154
+ -- Total cost by endpoint (last 7 days)
155
+ SELECT endpoint, deployment, COUNT(*) as calls, SUM(cost_usd) as total_cost
156
+ FROM ai_llm_usage_logs
157
+ WHERE api_name = 'snapshot' AND created_at > NOW() - INTERVAL 7 DAY
158
+ GROUP BY endpoint, deployment
159
+ ORDER BY total_cost DESC;
160
+ ```
161
+
162
+ ---
163
+
164
+ ## For Manual Scripts (No FastAPI)
165
+
166
+ Load env vars and call `flush()` before exit:
167
+
168
+ ```python
169
+ from dotenv import load_dotenv
170
+ from llm_tracker import TrackedOpenAI
171
+ from llm_tracker.logger import flush
172
+
173
+ load_dotenv()
174
+
175
+ client = TrackedOpenAI(api_key="...")
176
+ response = client.chat.completions.create(
177
+ model="gpt-4o",
178
+ messages=[...]
179
+ )
180
+
181
+ flush() # ensure background writes finish before script exits
182
+ ```
183
+
184
+ ---
185
+
186
+ ## Supported Models
187
+
188
+ Built-in pricing for:
189
+ - `gpt-4o` — $0.0025 input / $0.01 output per 1K tokens
190
+ - `gpt-4o-mini` — $0.00015 input / $0.0006 output per 1K tokens
191
+ - `gpt-4.1` — $0.002 input / $0.008 output per 1K tokens
192
+
193
+ Unknown models log `$0.00` cost. Override pricing with `LLM_TRACKER_PRICING_JSON`.
194
+
195
+ ---
196
+
197
+ ## Async Support
198
+
199
+ For async apps, use `TrackedAsyncOpenAI` / `TrackedAsyncAzureOpenAI` — same API, `await` the call:
200
+
201
+ ```python
202
+ from llm_tracker import TrackedAsyncOpenAI
203
+ from llm_tracker.logger import aflush
204
+
205
+ client = TrackedAsyncOpenAI(api_key="...")
206
+ response = await client.chat.completions.create(
207
+ model="gpt-4o",
208
+ messages=[{"role": "user", "content": "hello"}],
209
+ )
210
+
211
+ await aflush() # async-friendly equivalent of flush()
212
+ ```
213
+
214
+ ## Known Limitations
215
+
216
+ - ❌ Streaming (`stream=True`) not supported
217
+ - ❌ Embeddings not tracked (by design — cheap)
218
+ - ✓ Sync and async OpenAI/AzureOpenAI clients supported
219
+
220
+ ---
221
+
222
+ ## Support
223
+
224
+ - **Issues**: GitHub issues
225
+ - **Docs**: See `.env.example` and `schema.sql`
226
+ - **Examples**: `example_usage.py`
@@ -0,0 +1,24 @@
1
+ from dotenv import load_dotenv
2
+
3
+ # Load .env before any submodule reads os.environ at import time, regardless
4
+ # of whether/when the consuming application calls load_dotenv() itself.
5
+ load_dotenv()
6
+
7
+ from .client import (
8
+ TrackedAsyncAzureOpenAI,
9
+ TrackedAsyncOpenAI,
10
+ TrackedAzureOpenAI,
11
+ TrackedOpenAI,
12
+ request_ctx,
13
+ )
14
+
15
+ __version__ = "0.2.0"
16
+
17
+ __all__ = [
18
+ "TrackedAzureOpenAI",
19
+ "TrackedOpenAI",
20
+ "TrackedAsyncAzureOpenAI",
21
+ "TrackedAsyncOpenAI",
22
+ "request_ctx",
23
+ "__version__",
24
+ ]