惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

TaoSecurity Blog
TaoSecurity Blog
博客园 - 司徒正美
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 【当耐特】
M
MIT News - Artificial intelligence
罗磊的独立博客
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Stack Overflow Blog
Stack Overflow Blog
The GitHub Blog
The GitHub Blog
Google DeepMind News
Google DeepMind News
Security Archives - TechRepublic
Security Archives - TechRepublic
宝玉的分享
宝玉的分享
N
News and Events Feed by Topic
The Hacker News
The Hacker News
Google DeepMind News
Google DeepMind News
C
CERT Recently Published Vulnerability Notes
F
Full Disclosure
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Security @ Cisco Blogs
H
Hacker News: Front Page
L
LangChain Blog
Microsoft Security Blog
Microsoft Security Blog
Y
Y Combinator Blog
B
Blog RSS Feed
H
Heimdal Security Blog
Google Online Security Blog
Google Online Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 三生石上(FineUI控件)
V2EX - 技术
V2EX - 技术
V
Vulnerabilities – Threatpost
Help Net Security
Help Net Security
Hacker News - Newest:
Hacker News - Newest: "LLM"
T
Tailwind CSS Blog
W
WeLiveSecurity
T
Tenable Blog
D
DataBreaches.Net
Martin Fowler
Martin Fowler
Cyberwarzone
Cyberwarzone
Cisco Talos Blog
Cisco Talos Blog
S
Secure Thoughts
O
OpenAI News
L
LINUX DO - 热门话题
Vercel News
Vercel News
阮一峰的网络日志
阮一峰的网络日志
Jina AI
Jina AI
J
Java Code Geeks
Know Your Adversary
Know Your Adversary
IT之家
IT之家
Latest news
Latest news
Cloudbric
Cloudbric

OpenAI Developers

API deployment checklist | OpenAI API Sora 2 Prompting Guide Codex Prompting Guide Docs MCP | OpenAI Developers Gpt-image-1.5 Prompting Guide GPT-5.2 Prompting Guide Transcribing User Audio with a Separate Realtime Request Modernizing your Codebase with Codex GitHub - openai/openai-sora-sample-app: Sample app to get started using the Video API with Sora GitHub - openai/openai-apps-sdk-examples: Example apps for the Apps SDK GitHub - openai/openai-chatkit-advanced-samples: Starter app to build with OpenAI ChatKit SDK GitHub - openai/openai-chatkit-starter-app: Starter app to build with OpenAI ChatKit + Agent Builder Rate limits | OpenAI API Web search | OpenAI API Getting started with datasets | OpenAI API Prompt optimizer | OpenAI API Verifying gpt-oss implementations How to run gpt-oss locally with LM Studio Fine-tuning with gpt-oss and Hugging Face Transformers How to run gpt-oss locally with Ollama Function calling | OpenAI API Models | OpenAI API Reasoning best practices | OpenAI API Reasoning models | OpenAI API Background mode | OpenAI API Batch API | OpenAI API Conversation state | OpenAI API File search | OpenAI API Flex processing | OpenAI API MCP and Connectors | OpenAI API Code Interpreter | OpenAI API Quickstart - OpenAI Agents SDK Build Hour: Agentic Tool Calling Build Hour: Built-In Tools Reasoning best practices | OpenAI API Graders | OpenAI API Evaluation best practices | OpenAI API Working with evals | OpenAI API Guardrails - OpenAI Agents SDK Latency optimization | OpenAI API Optimizing LLM Accuracy | OpenAI API Agent orchestration - OpenAI Agents SDK Production best practices | OpenAI API Realtime transcription | OpenAI API Optimizing LLM Accuracy | OpenAI API Realtime and audio | OpenAI API Realtime conversations | OpenAI API Responses guide Migrate to the Responses API | OpenAI API Speech to text | OpenAI API Supervised fine-tuning | OpenAI API Tracing - OpenAI Agents SDK Vision fine-tuning | OpenAI API Audio and speech | OpenAI API GitHub - openai/openai-cs-agents-demo: Demo of a customer service use case implemented with the OpenAI Agents SDK Voice agents | OpenAI API Fine-tuning best practices | OpenAI API GitHub - openai/openai-agents-python: A lightweight, powerful framework for multi-agent workflows GitHub - openai/openai-agents-js: A lightweight, powerful framework for multi-agent workflows and voice agents Agents SDK | OpenAI API Using tools | OpenAI API Computer use | OpenAI API GitHub - openai/openai-cua-sample-app: Learn how to use CUA (our Computer Using Agent) via the API on multiple computer environments. GitHub - openai/openai-testing-agent-demo: Demo of a UI testing agent using the OpenAI CUA model and the Responses API. Model optimization | OpenAI API GitHub - openai/openai-fm: Code for openai.fm, a demo for the OpenAI Speech API Predicted Outputs | OpenAI API GitHub - openai/openai-realtime-console: React app for inspecting, building and debugging with the Realtime API Building Voice Agents GitHub - openai/openai-realtime-solar-system: Demo showing how to use the OpenAI Realtime API to navigate a 3D scene via tool calling GitHub - openai/openai-realtime-twilio-demo Reinforcement fine-tuning | OpenAI API GitHub - openai/openai-responses-starter-app: Starter app to build with the OpenAI Responses API Structured model outputs | OpenAI API GitHub - openai/openai-structured-outputs-samples: Sample apps to help developers get started with Structured Outputs Voice agents | OpenAI API Model optimization | OpenAI API GitHub - openai/openai-realtime-agents: This is a simple demonstration of more advanced, agentic patterns built on top of the Realtime API. GitHub - openai/openai-support-agent-demo: Demo of a customer support agent interface using NextJS and the OpenAI Responses API with File Search Building Voice Agents Generate images with high input fidelity AI app development: Concept to production Model optimization Building agents Eval Driven System Design - From Prototype to Production Multi-Agent Portfolio Collaboration with OpenAI Agents SDK o3/o4-mini Function Calling Guide Exploring Model Graders for Reinforcement Fine-Tuning Guide to Using the Responses API Reinforcement Fine-Tuning for Conversational Reasoning with the OpenAI API Evals API Use-case - Responses Evaluation Comparing Speech-to-Text Methods with the OpenAI API Generate images with GPT Image Multi-Tool Orchestration with RAG approach using OpenAI Multi-Language One-Way Translation with the Realtime API Doing RAG on PDFs using File Search in the Responses API Leveraging model distillation to fine-tune a model Orchestrating Agents: Routines and Handoffs Prompt Caching 101 Developing Hallucination Guardrails
How to use the Usage API and Cost API to monitor your OpenAI usage
2025-01-14 · via OpenAI Developers

For most of our users, the default usage and cost dashboards are sufficient. However, if you need more detailed data or a custom dashboard, you can use the Completions Usage API.

This notebook demonstrates how to retrieve and visualize usage data from the OpenAI Completions Usage API and Costs API. We’ll:

  • Call the API to get completions usage data.
  • Parse the JSON response into a pandas DataFrame.
  • Visualize token usage over time using matplotlib.
  • Use grouping by model to analyze token usage across different models.
  • Display model distribution with a pie chart.

We also include placeholders for all possible API parameters for a comprehensive overview.

# Install required libraries (if not already installed)
!pip install requests pandas numpy matplotlib --quiet

# Import libraries
import requests
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import time
import json

# For inline plotting in Jupyter
%matplotlib inline

Set up an Admin Key - https://platform.openai.com/settings/organization/admin-keys

Replace 'PLACEHOLDER' with your actual ADMIN API key. It’s best practice to load the key from an environment variable for security.

# Reusable function for retrieving paginated data from the API
def get_data(url, params):
    # Set up the API key and headers
    OPENAI_ADMIN_KEY = 'PLACEHOLDER'

    headers = {
        "Authorization": f"Bearer {OPENAI_ADMIN_KEY}",
        "Content-Type": "application/json",
    }

    # Initialize an empty list to store all data
    all_data = []

    # Initialize pagination cursor
    page_cursor = None

    # Loop to handle pagination
    while True:
        if page_cursor:
            params["page"] = page_cursor

        response = requests.get(url, headers=headers, params=params)

        if response.status_code == 200:
            data_json = response.json()
            all_data.extend(data_json.get("data", []))

            page_cursor = data_json.get("next_page")
            if not page_cursor:
                break
        else:
            print(f"Error: {response.status_code}")
            break

    if all_data:
        print("Data retrieved successfully!")
    else:
        print("Issue: No data available to retrieve.")
    return all_data
# Define the API endpoint
url = "https://api.openai.com/v1/organization/usage/completions"

# Calculate start time: n days ago from now
days_ago = 30
start_time = int(time.time()) - (days_ago * 24 * 60 * 60)

# Define parameters with placeholders for all possible options
params = {
    "start_time": start_time,  # Required: Start time (Unix seconds)
    # "end_time": end_time,  # Optional: End time (Unix seconds)
    "bucket_width": "1d",  # Optional: '1m', '1h', or '1d' (default '1d')
    # "project_ids": ["proj_example"],  # Optional: List of project IDs
    # "user_ids": ["user_example"],     # Optional: List of user IDs
    # "api_key_ids": ["key_example"],   # Optional: List of API key IDs
    # "models": ["o1-2024-12-17", "gpt-4o-2024-08-06", "gpt-4o-mini-2024-07-18"],  # Optional: List of models
    # "batch": False,             # Optional: True for batch jobs, False for non-batch
    # "group_by": ["model"],     # Optional: Fields to group by
    "limit": 7,  # Optional: Number of buckets to return, this will chunk the data into 7 buckets
    # "page": "cursor_string"   # Optional: Cursor for pagination
}

usage_data = get_data(url, params)
Data retrieved successfully!

Let’s take a look at the raw JSON response from the API to understand its structure.

print(json.dumps(usage_data, indent=2))
[
  {
    "object": "bucket",
    "start_time": 1736616660,
    "end_time": 1736640000,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 141201,
        "output_tokens": 9756,
        "num_model_requests": 470,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1736640000,
    "end_time": 1736726400,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 45949,
        "output_tokens": 282,
        "num_model_requests": 150,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1736726400,
    "end_time": 1736812800,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 3718360,
        "output_tokens": 97756,
        "num_model_requests": 3053,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 76544,
        "input_audio_tokens": 5776,
        "output_audio_tokens": 3166
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1736812800,
    "end_time": 1736899200,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 52786,
        "output_tokens": 38204,
        "num_model_requests": 157,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 5440,
        "input_audio_tokens": 4066,
        "output_audio_tokens": 1097
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1736899200,
    "end_time": 1736985600,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 35664,
        "output_tokens": 1835,
        "num_model_requests": 55,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 192,
        "input_audio_tokens": 2520,
        "output_audio_tokens": 1549
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1736985600,
    "end_time": 1737072000,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 5464,
        "output_tokens": 2667,
        "num_model_requests": 8,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737072000,
    "end_time": 1737158400,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 3390547,
        "output_tokens": 38604,
        "num_model_requests": 2687,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 25344,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737158400,
    "end_time": 1737244800,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 8117824,
        "output_tokens": 105662,
        "num_model_requests": 6335,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 46464,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737244800,
    "end_time": 1737331200,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 13542,
        "output_tokens": 85,
        "num_model_requests": 46,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737331200,
    "end_time": 1737417600,
    "results": []
  },
  {
    "object": "bucket",
    "start_time": 1737417600,
    "end_time": 1737504000,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 29806,
        "output_tokens": 57604,
        "num_model_requests": 98,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737504000,
    "end_time": 1737590400,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 1823,
        "output_tokens": 1467,
        "num_model_requests": 7,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737590400,
    "end_time": 1737676800,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 7126,
        "output_tokens": 1896,
        "num_model_requests": 19,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737676800,
    "end_time": 1737763200,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 22187,
        "output_tokens": 822,
        "num_model_requests": 75,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 640,
        "input_audio_tokens": 2557,
        "output_audio_tokens": 3103
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737763200,
    "end_time": 1737849600,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 30204,
        "output_tokens": 65673,
        "num_model_requests": 99,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737849600,
    "end_time": 1737936000,
    "results": []
  },
  {
    "object": "bucket",
    "start_time": 1737936000,
    "end_time": 1738022400,
    "results": []
  },
  {
    "object": "bucket",
    "start_time": 1738022400,
    "end_time": 1738108800,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 2541,
        "output_tokens": 1604,
        "num_model_requests": 14,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738108800,
    "end_time": 1738195200,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 68339,
        "output_tokens": 49525,
        "num_model_requests": 217,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 7296,
        "input_audio_tokens": 20033,
        "output_audio_tokens": 3168
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738195200,
    "end_time": 1738281600,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 18481,
        "output_tokens": 17500,
        "num_model_requests": 84,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 2944,
        "input_audio_tokens": 10076,
        "output_audio_tokens": 4966
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738281600,
    "end_time": 1738368000,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 1187894,
        "output_tokens": 139134,
        "num_model_requests": 5528,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 2112,
        "input_audio_tokens": 4935,
        "output_audio_tokens": 993
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738368000,
    "end_time": 1738454400,
    "results": []
  },
  {
    "object": "bucket",
    "start_time": 1738454400,
    "end_time": 1738540800,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 7268,
        "output_tokens": 30563,
        "num_model_requests": 24,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738540800,
    "end_time": 1738627200,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 15121,
        "output_tokens": 22866,
        "num_model_requests": 48,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738627200,
    "end_time": 1738713600,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 16735,
        "output_tokens": 16177,
        "num_model_requests": 50,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 1152,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738713600,
    "end_time": 1738800000,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 6573,
        "output_tokens": 4238,
        "num_model_requests": 43,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738800000,
    "end_time": 1738886400,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 1402,
        "output_tokens": 2042,
        "num_model_requests": 18,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738886400,
    "end_time": 1738972800,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 11847,
        "output_tokens": 21938,
        "num_model_requests": 47,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738972800,
    "end_time": 1739059200,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 1993,
        "output_tokens": 12,
        "num_model_requests": 7,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1739059200,
    "end_time": 1739145600,
    "results": []
  },
  {
    "object": "bucket",
    "start_time": 1739145600,
    "end_time": 1739208663,
    "results": [
      {
        "object": "organization.usage.completions.result",
        "input_tokens": 332,
        "output_tokens": 1509,
        "num_model_requests": 8,
        "project_id": null,
        "user_id": null,
        "api_key_id": null,
        "model": null,
        "batch": null,
        "input_cached_tokens": 0,
        "input_audio_tokens": 0,
        "output_audio_tokens": 0
      }
    ]
  }
]

Now we will parse the JSON data, extract relevant fields, and create a pandas DataFrame for easier manipulation and analysis.

# Initialize a list to hold parsed records
records = []

# Iterate through the data to extract bucketed data
for bucket in usage_data:
    start_time = bucket.get("start_time")
    end_time = bucket.get("end_time")
    for result in bucket.get("results", []):
        records.append(
            {
                "start_time": start_time,
                "end_time": end_time,
                "input_tokens": result.get("input_tokens", 0),
                "output_tokens": result.get("output_tokens", 0),
                "input_cached_tokens": result.get("input_cached_tokens", 0),
                "input_audio_tokens": result.get("input_audio_tokens", 0),
                "output_audio_tokens": result.get("output_audio_tokens", 0),
                "num_model_requests": result.get("num_model_requests", 0),
                "project_id": result.get("project_id"),
                "user_id": result.get("user_id"),
                "api_key_id": result.get("api_key_id"),
                "model": result.get("model"),
                "batch": result.get("batch"),
            }
        )

# Create a DataFrame from the records
df = pd.DataFrame(records)

# Convert Unix timestamps to datetime for readability
df["start_datetime"] = pd.to_datetime(df["start_time"], unit="s")
df["end_datetime"] = pd.to_datetime(df["end_time"], unit="s")

# Reorder columns for better readability
df = df[
    [
        "start_datetime",
        "end_datetime",
        "start_time",
        "end_time",
        "input_tokens",
        "output_tokens",
        "input_cached_tokens",
        "input_audio_tokens",
        "output_audio_tokens",
        "num_model_requests",
        "project_id",
        "user_id",
        "api_key_id",
        "model",
        "batch",
    ]
]

# Display the DataFrame
df.head()
start_datetime end_datetime start_time end_time input_tokens output_tokens input_cached_tokens input_audio_tokens output_audio_tokens num_model_requests project_id user_id api_key_id model batch
0 2025-01-11 17:31:00 2025-01-12 1736616660 1736640000 141201 9756 0 0 0 470 None None None None None
1 2025-01-12 00:00:00 2025-01-13 1736640000 1736726400 45949 282 0 0 0 150 None None None None None
2 2025-01-13 00:00:00 2025-01-14 1736726400 1736812800 3718360 97756 76544 5776 3166 3053 None None None None None
3 2025-01-14 00:00:00 2025-01-15 1736812800 1736899200 52786 38204 5440 4066 1097 157 None None None None None
4 2025-01-15 00:00:00 2025-01-16 1736899200 1736985600 35664 1835 192 2520 1549 55 None None None None None

We’ll create a bar chart to visualize input and output token usage for each time bucket.

if not df.empty:
    plt.figure(figsize=(12, 6))

    # Create bar charts for input and output tokens
    width = 0.35  # width of the bars
    indices = range(len(df))

    plt.bar(indices, df["input_tokens"], width=width, label="Input Tokens", alpha=0.7)
    plt.bar(
        [i + width for i in indices],
        df["output_tokens"],
        width=width,
        label="Output Tokens",
        alpha=0.7,
    )

    # Set labels and ticks
    plt.xlabel("Time Bucket")
    plt.ylabel("Number of Tokens")
    plt.title("Daily Input vs Output Token Usage Last 30 Days")
    plt.xticks(
        [i + width / 2 for i in indices],
        [dt.strftime("%Y-%m-%d") for dt in df["start_datetime"]],
        rotation=45,
    )
    plt.legend()
    plt.tight_layout()
    plt.show()
else:
    print("No data available to plot.")

In this section, we retrieve and visualize usage data grouped by model and project_id. This can help you see the total tokens used by each model over the specified period.

Note on Grouping Parameter

  • If you do not specify a group_by parameter, fields such as project_id, model, and others will return as null. Although the group_by parameter is optional, it is recommended to include it in most cases to retrieve meaningful data.

  • You can specify multiple group fields by separating them with commas. For example: group_by=["model", "project_id"].

# Calculate start time: n days ago from now
days_ago = 30
start_time = int(time.time()) - (days_ago * 24 * 60 * 60)

# Define parameters with grouping by model and project_id
params = {
    "start_time": start_time,  # Required: Start time (Unix seconds)
    "bucket_width": "1d",  # Optional: '1m', '1h', or '1d' (default '1d')
    "group_by": ["model", "project_id"],  # Group data by model and project_id
    "limit": 7,  # Optional: Number of buckets to return
}

# Initialize an empty list to store all data
all_group_data = get_data(url, params)

# Initialize a list to hold parsed records
records = []

# Iterate through the data to extract bucketed data
for bucket in all_group_data:
    start_time = bucket.get("start_time")
    end_time = bucket.get("end_time")
    for result in bucket.get("results", []):
        records.append(
            {
                "start_time": start_time,
                "end_time": end_time,
                "input_tokens": result.get("input_tokens", 0),
                "output_tokens": result.get("output_tokens", 0),
                "input_cached_tokens": result.get("input_cached_tokens", 0),
                "input_audio_tokens": result.get("input_audio_tokens", 0),
                "output_audio_tokens": result.get("output_audio_tokens", 0),
                "num_model_requests": result.get("num_model_requests", 0),
                "project_id": result.get("project_id", "N/A"),
                "user_id": result.get("user_id", "N/A"),
                "api_key_id": result.get("api_key_id", "N/A"),
                "model": result.get("model", "N/A"),
                "batch": result.get("batch", "N/A"),
            }
        )

# Create a DataFrame from the records
df = pd.DataFrame(records)

# Convert Unix timestamps to datetime for readability
df["start_datetime"] = pd.to_datetime(df["start_time"], unit="s", errors="coerce")
df["end_datetime"] = pd.to_datetime(df["end_time"], unit="s", errors="coerce")

# Reorder columns for better readability
df = df[
    [
        "start_datetime",
        "end_datetime",
        "start_time",
        "end_time",
        "input_tokens",
        "output_tokens",
        "input_cached_tokens",
        "input_audio_tokens",
        "output_audio_tokens",
        "num_model_requests",
        "project_id",
        "user_id",
        "api_key_id",
        "model",
        "batch",
    ]
]

# Display the DataFrame
df.head()
Data retrieved successfully!
start_datetime end_datetime start_time end_time input_tokens output_tokens input_cached_tokens input_audio_tokens output_audio_tokens num_model_requests project_id user_id api_key_id model batch
0 2025-01-11 17:31:39 2025-01-12 1736616699 1736640000 6897 97 0 0 0 97 proj_hNhhQzyYu7HxySZWs7cA3Ugu None None gpt-4o-mini-2024-07-18 None
1 2025-01-11 17:31:39 2025-01-12 1736616699 1736640000 33984 206 0 0 0 95 proj_hNhhQzyYu7HxySZWs7cA3Ugu None None ft:gpt-4o-2024-08-06:distillation-test:wordle2... None
2 2025-01-11 17:31:39 2025-01-12 1736616699 1736640000 2846 8874 0 0 0 8 proj_hNhhQzyYu7HxySZWs7cA3Ugu None None o1-mini-2024-09-12 None
3 2025-01-11 17:31:39 2025-01-12 1736616699 1736640000 97474 579 0 0 0 270 proj_hNhhQzyYu7HxySZWs7cA3Ugu None None gpt-4o-2024-08-06 None
4 2025-01-12 00:00:00 2025-01-13 1736640000 1736726400 1989 28 0 0 0 28 proj_hNhhQzyYu7HxySZWs7cA3Ugu None None gpt-4o-mini-2024-07-18 None

Now we will parse the JSON data, extract relevant fields, and create a pandas DataFrame for easier manipulation and analysis.

# Group data by model and project_id and aggregate model request counts
grouped_by_model_project = (
    df.groupby(["model", "project_id"])
    .agg(
        {
            "num_model_requests": "sum",
        }
    )
    .reset_index()
)

# Determine unique models and project IDs for plotting and color mapping
models = sorted(grouped_by_model_project["model"].unique())
project_ids = sorted(grouped_by_model_project["project_id"].unique())
distinct_colors = [
    "#1f77b4",
    "#ff7f0e",
    "#2ca02c",
    "#d62728",
    "#9467bd",
    "#8c564b",
    "#e377c2",
    "#7f7f7f",
    "#bcbd22",
    "#17becf",
]
project_color_mapping = {
    pid: distinct_colors[i % len(distinct_colors)] for i, pid in enumerate(project_ids)
}

# Calculate total number of requests per project_id for legend
project_totals = (
    grouped_by_model_project.groupby("project_id")["num_model_requests"]
    .sum()
    .sort_values(ascending=False)  # Sort by highest total first
)

# Set up bar positions
n_models = len(models)
bar_width = 0.6
x = np.arange(n_models)

plt.figure(figsize=(12, 6))

# Plot stacked bars for each model
for model_idx, model in enumerate(models):
    # Filter data for the current model
    model_data = grouped_by_model_project[grouped_by_model_project["model"] == model]

    bottom = 0
    # Stack segments for each project ID within the bars
    for _, row in model_data.iterrows():
        color = project_color_mapping[row["project_id"]]
        plt.bar(
            x[model_idx],
            row["num_model_requests"],
            width=bar_width,
            bottom=bottom,
            color=color,
        )
        bottom += row["num_model_requests"]

# Labeling and styling
plt.xlabel("Model")
plt.ylabel("Number of Model Requests")
plt.title("Total Model Requests by Model and Project ID Last 30 Days")
plt.xticks(x, models, rotation=45, ha="right")

# Create a sorted legend with totals
handles = [
    mpatches.Patch(color=project_color_mapping[pid], label=f"{pid} (Total: {total})")
    for pid, total in project_totals.items()
]
plt.legend(handles=handles, bbox_to_anchor=(1.05, 1), loc="upper left")

plt.tight_layout()
plt.show()

This section visualizes the distribution of token usage across different models using a pie chart.

records = []
for bucket in all_group_data:
    for result in bucket.get("results", []):
        records.append(
            {
                "project_id": result.get("project_id", "N/A"),
                "num_model_requests": result.get("num_model_requests", 0),
            }
        )

# Create a DataFrame
df = pd.DataFrame(records)

# Aggregate data by project_id
grouped_by_project = (
    df.groupby("project_id").agg({"num_model_requests": "sum"}).reset_index()
)

# Visualize Pie Chart
if not grouped_by_project.empty:
    # Filter out rows where num_model_requests == 0
    filtered_grouped_by_project = grouped_by_project[
        grouped_by_project["num_model_requests"] > 0
    ]

    # Calculate the total model requests after filtering
    total_requests = filtered_grouped_by_project["num_model_requests"].sum()

    if total_requests > 0:
        # Calculate percentage of total for each project
        filtered_grouped_by_project["percentage"] = (
            filtered_grouped_by_project["num_model_requests"] / total_requests
        ) * 100

        # Separate "Other" projects (below 5%)
        other_projects = filtered_grouped_by_project[
            filtered_grouped_by_project["percentage"] < 5
        ]
        main_projects = filtered_grouped_by_project[
            filtered_grouped_by_project["percentage"] >= 5
        ]

        # Sum up "Other" projects
        if not other_projects.empty:
            other_row = pd.DataFrame(
                {
                    "project_id": ["Other"],
                    "num_model_requests": [other_projects["num_model_requests"].sum()],
                    "percentage": [other_projects["percentage"].sum()],
                }
            )
            filtered_grouped_by_project = pd.concat(
                [main_projects, other_row], ignore_index=True
            )

        # Sort by number of requests for better legend organization
        filtered_grouped_by_project = filtered_grouped_by_project.sort_values(
            by="num_model_requests", ascending=False
        )

        # Main pie chart for distribution of model requests by project_id
        plt.figure(figsize=(10, 8))
        plt.pie(
            filtered_grouped_by_project["num_model_requests"],
            labels=filtered_grouped_by_project["project_id"],
            autopct=lambda p: f"{p:.1f}%\n({int(p * total_requests / 100):,})",
            startangle=140,
            textprops={"fontsize": 10},
        )
        plt.title("Distribution of Model Requests by Project ID", fontsize=14)
        plt.axis("equal")  # Equal aspect ratio ensures pie chart is circular.
        plt.tight_layout()
        plt.show()

        # If there are "Other" projects, generate a second pie chart for breakdown
        if not other_projects.empty:
            other_total_requests = other_projects["num_model_requests"].sum()

            plt.figure(figsize=(10, 8))
            plt.pie(
                other_projects["num_model_requests"],
                labels=other_projects["project_id"],
                autopct=lambda p: f"{p:.1f}%\n({int(p * other_total_requests / 100):,})",
                startangle=140,
                textprops={"fontsize": 10},
            )
            plt.title('Breakdown of "Other" Projects by Model Requests', fontsize=14)
            plt.axis("equal")  # Equal aspect ratio ensures pie chart is circular.
            plt.tight_layout()
            plt.show()
    else:
        print("Total model requests is zero. Pie chart will not be rendered.")
else:
    print("No grouped data available for pie chart.")

In this section, we’ll work with the OpenAI Costs API to retrieve and visualize cost data. Similar to the completions data, we’ll:

  • Call the Costs API to get aggregated cost data.
  • Parse the JSON response into a pandas DataFrame.
  • Visualize costs grouped by line item using a bar chart.
# Calculate start time: n days ago from now
days_ago = 30
start_time = int(time.time()) - (days_ago * 24 * 60 * 60)

# Define the Costs API endpoint
costs_url = "https://api.openai.com/v1/organization/costs"

costs_params = {
    "start_time": start_time,  # Required: Start time (Unix seconds)
    "bucket_width": "1d",  # Optional: Currently only '1d' is supported
    "limit": 30,  # Optional: Number of buckets to return
}

# Initialize an empty list to store all data
all_costs_data = get_data(costs_url, costs_params)
Data retrieved successfully!
print(json.dumps(all_costs_data, indent=2))
[
  {
    "object": "bucket",
    "start_time": 1736553600,
    "end_time": 1736640000,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.13080438340307526,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1736640000,
    "end_time": 1736726400,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.12270423340307525,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1736726400,
    "end_time": 1736812800,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 9.888144383403077,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1736812800,
    "end_time": 1736899200,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.3507639334030752,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1736899200,
    "end_time": 1736985600,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.2977481185324674,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1736985600,
    "end_time": 1737072000,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.00925485477848094,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737072000,
    "end_time": 1737158400,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 8.889884136532304,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737158400,
    "end_time": 1737244800,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 21.167310118127915,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737244800,
    "end_time": 1737331200,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.04955636812791847,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737331200,
    "end_time": 1737417600,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.0003226181279184669,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737417600,
    "end_time": 1737504000,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.6320363681279185,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737504000,
    "end_time": 1737590400,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 52.41558761812793,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737590400,
    "end_time": 1737676800,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 104.88761235323427,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737676800,
    "end_time": 1737763200,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.3376030385950106,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737763200,
    "end_time": 1737849600,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.062551042553524,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737849600,
    "end_time": 1737936000,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.00032195744715549047,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1737936000,
    "end_time": 1738022400,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.0003084210662774742,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738022400,
    "end_time": 1738108800,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.00032195744715549047,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738108800,
    "end_time": 1738195200,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.5142559074471554,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738195200,
    "end_time": 1738281600,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.21870350744715547,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738281600,
    "end_time": 1738368000,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 1.4528752074471551,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738368000,
    "end_time": 1738454400,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.00042714787262957543,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738454400,
    "end_time": 1738540800,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.00032195744715549047,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738540800,
    "end_time": 1738627200,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.0031147346857709622,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738627200,
    "end_time": 1738713600,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 68.30023964957941,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738713600,
    "end_time": 1738800000,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 14.858330207447157,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738800000,
    "end_time": 1738886400,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.3137180574471555,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738886400,
    "end_time": 1738972800,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.02677460744715549,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1738972800,
    "end_time": 1739059200,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.007399792553524012,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1739059200,
    "end_time": 1739145600,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.00032195744715549047,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  },
  {
    "object": "bucket",
    "start_time": 1739145600,
    "end_time": 1739232000,
    "results": [
      {
        "object": "organization.costs.result",
        "amount": {
          "value": 0.00012073404268330895,
          "currency": "usd"
        },
        "line_item": null,
        "project_id": null,
        "organization_id": "org-GLHrIv00VVN9dEQC2b4wsBkf"
      }
    ]
  }
]

We will now parse the JSON data from the Costs API, extract relevant fields, and create a pandas DataFrame for further analysis.

# Initialize a list to hold parsed cost records
cost_records = []

# Extract bucketed cost data from all_costs_data
for bucket in all_costs_data:
    start_time = bucket.get("start_time")
    end_time = bucket.get("end_time")
    for result in bucket.get("results", []):
        cost_records.append(
            {
                "start_time": start_time,
                "end_time": end_time,
                "amount_value": result.get("amount", {}).get("value", 0),
                "currency": result.get("amount", {}).get("currency", "usd"),
                "line_item": result.get("line_item"),
                "project_id": result.get("project_id"),
            }
        )

# Create a DataFrame from the cost records
cost_df = pd.DataFrame(cost_records)

# Convert Unix timestamps to datetime for readability
cost_df["start_datetime"] = pd.to_datetime(cost_df["start_time"], unit="s")
cost_df["end_datetime"] = pd.to_datetime(cost_df["end_time"], unit="s")

# Display the first few rows of the DataFrame
cost_df.head()
start_time end_time amount_value currency line_item project_id start_datetime end_datetime
0 1736553600 1736640000 0.130804 usd None None 2025-01-11 2025-01-12
1 1736640000 1736726400 0.122704 usd None None 2025-01-12 2025-01-13
2 1736726400 1736812800 9.888144 usd None None 2025-01-13 2025-01-14
3 1736812800 1736899200 0.350764 usd None None 2025-01-14 2025-01-15
4 1736899200 1736985600 0.297748 usd None None 2025-01-15 2025-01-16

We’ll create a bar chart to visualize the total costs aggregated by day. This helps give a high level perspective on organizational spend.

if not cost_df.empty:
    # Ensure datetime conversion for 'start_datetime' column
    if (
        "start_datetime" not in cost_df.columns
        or not pd.api.types.is_datetime64_any_dtype(cost_df["start_datetime"])
    ):
        cost_df["start_datetime"] = pd.to_datetime(
            cost_df["start_time"], unit="s", errors="coerce"
        )

    # Create a new column for just the date part of 'start_datetime'
    cost_df["date"] = cost_df["start_datetime"].dt.date

    # Group by date and sum the amounts
    cost_per_day = cost_df.groupby("date")["amount_value"].sum().reset_index()

    # Plot the data
    plt.figure(figsize=(12, 6))
    plt.bar(
        cost_per_day["date"],
        cost_per_day["amount_value"],
        width=0.6,
        color="skyblue",
        alpha=0.8,
    )
    plt.xlabel("Date")
    plt.ylabel("Total Cost (USD)")
    plt.title("Total Cost per Day (Last 30 Days)")
    plt.xticks(rotation=45, ha="right")
    plt.tight_layout()
    plt.show()
else:
    print("No cost data available to plot.")

We’ll create a bar chart to visualize the total costs aggregated by line item. This helps identify which categories (e.g., models or other services) contribute most to the expenses.

days_ago = 30
start_time = int(time.time()) - (days_ago * 24 * 60 * 60)

costs_params = {
    "start_time": start_time,  # Required: Start time (Unix seconds)
    "bucket_width": "1d",  # Optional: Currently only '1d' is supported
    "limit": 30,  # Optional: Number of buckets to return
    "group_by": ["line_item"],
}

line_item_cost_data = get_data(costs_url, costs_params)

# Initialize a list to hold parsed cost records
cost_records = []

# Extract bucketed cost data from all_costs_data
for bucket in line_item_cost_data:
    start_time = bucket.get("start_time")
    end_time = bucket.get("end_time")
    for result in bucket.get("results", []):
        cost_records.append(
            {
                "start_time": start_time,
                "end_time": end_time,
                "amount_value": result.get("amount", {}).get("value", 0),
                "currency": result.get("amount", {}).get("currency", "usd"),
                "line_item": result.get("line_item"),
                "project_id": result.get("project_id"),
            }
        )

# Create a DataFrame from the cost records
cost_df = pd.DataFrame(cost_records)

# Convert Unix timestamps to datetime for readability
cost_df["start_datetime"] = pd.to_datetime(cost_df["start_time"], unit="s")
cost_df["end_datetime"] = pd.to_datetime(cost_df["end_time"], unit="s")

# Display the first few rows of the DataFrame
cost_df.head()
Data retrieved successfully!
start_time end_time amount_value currency line_item project_id start_datetime end_datetime
0 1736553600 1736640000 0.127440 usd ft-gpt-4o-2024-08-06, input proj_hNhhQzyYu7HxySZWs7cA3Ugu 2025-01-11 2025-01-12
1 1736553600 1736640000 0.003090 usd ft-gpt-4o-2024-08-06, output proj_hNhhQzyYu7HxySZWs7cA3Ugu 2025-01-11 2025-01-12
2 1736553600 1736640000 0.000271 usd assistants api | file search proj_L67gOme4S2nBA8aQieEOwLy7 2025-01-11 2025-01-12
3 1736553600 1736640000 0.000003 usd assistants api | file search proj_VV4ZAjd6ALfFd9uh0vY8joR1 2025-01-11 2025-01-12
4 1736640000 1736726400 0.028607 usd evals | gpt-4o-mini-2024-07-18, input proj_L67gOme4S2nBA8aQieEOwLy7 2025-01-12 2025-01-13
if not cost_df.empty:
    # Ensure datetime conversion for 'start_datetime' column
    if "start_datetime" not in cost_df.columns or not pd.api.types.is_datetime64_any_dtype(cost_df["start_datetime"]):
        cost_df["start_datetime"] = pd.to_datetime(cost_df["start_time"], unit="s", errors="coerce")

    # Create a new column for just the date part of 'start_datetime'
    cost_df["date"] = cost_df["start_datetime"].dt.date

    # Group by date and line_item and sum the amounts
    cost_per_day = cost_df.groupby(["date", "line_item"])["amount_value"].sum().reset_index()

    # Pivot the DataFrame so each date has one bar with line_item stacks
    cost_pivot = cost_per_day.pivot(index="date", columns="line_item", values="amount_value").fillna(0)
    cost_pivot = cost_pivot.sort_index()

    # Plot a stacked bar chart with one bar for each grouped day
    plt.figure(figsize=(12, 6))
    ax = cost_pivot.plot(kind="bar", stacked=True, ax=plt.gca(), width=0.8)
    plt.xlabel("Date")
    plt.ylabel("Total Cost (USD)")
    plt.title("Total Cost by Line Item")
    plt.xticks(rotation=45, ha="right")
    # Update legend so it doesn't overlay the graph by placing it outside the plot area
    plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left", borderaxespad=0.)
    plt.tight_layout()
    plt.show()
else:
    print("No cost data available to plot.")
/var/folders/r_/g8r2dz8s2qd104th5p5yxljr0000gp/T/ipykernel_49468/2813361465.py:25: UserWarning: Tight layout not applied. The bottom and top margins cannot be made large enough to accommodate all Axes decorations.
  plt.tight_layout()

You can extend this notebook with more visualizations for both the Completions and Costs APIs. For example:

Completions API:

  • Group by user, project, or model to see which ones consume the most tokens.
  • Create line plots for time series analysis of token usage over days or hours.
  • Use pie charts to visualize distribution of tokens across models, users, or projects.
  • Experiment with different group_by parameters (e.g., ["model", "user_id"]) to gain deeper insights.

Costs API:

  • Group by project or line item to identify spending patterns.
  • Create line or bar charts to visualize daily cost trends.
  • Use pie charts to show how costs are distributed across projects, services, or line items.
  • Try various group_by options (e.g., ["project_id"], ["line_item"]) for granular analysis.

Experiment with different parameters and visualization techniques using pandas and matplotlib (or libraries like Plotly/Bokeh) to gain deeper insights, and consider integrating these visualizations into interactive dashboards for real-time monitoring.

To bring OpenAI usage and cost data into external dashboarding tools like Tableau, Power BI, or custom platforms (e.g., Plotly Dash, Bokeh), follow these steps:

  1. Data Collection & Preparation:

    • Use Python scripts to regularly fetch data from the Completions and Costs APIs.
    • Process and aggregate the data with pandas, then store it in a database, data warehouse, or export it as CSV/JSON files.
  2. Connecting to a Dashboard:

    • BI Tools (Tableau, Power BI):
      • Connect directly to the prepared data source (SQL database, CSV files, or web APIs).
      • Use built-in connectors to schedule data refreshes, ensuring dashboards always display current information.
    • Custom Dashboards (Plotly Dash, Bokeh):
      • Embed API calls and data processing into the dashboard code.
      • Build interactive visual components that automatically update as new data is fetched.
  3. Real-Time & Automated Updates:

    • Schedule scripts using cron jobs, task schedulers, or workflow tools (e.g., Apache Airflow) to refresh data periodically.
    • Implement webhooks or streaming APIs (if available) for near real-time data updates.

By integrating API data into third-party platforms, you can create interactive, real-time dashboards that combine OpenAI metrics with other business data, offering comprehensive insights and automated monitoring.