2025-01-15 15:39:19 +00:00
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# OpenAI Completions Usage API Extended Example\n",
"\n",
"For most of our users, the [default usage and cost dashboards](https://platform.openai.com/usage) are sufficient. However, if you need more detailed data or a custom dashboard, you can use the Completions Usage API.\n",
"\n",
"This notebook demonstrates how to retrieve and visualize usage data from the OpenAI Completions Usage API and Costs API. We'll:\n",
"- Call the API to get completions usage data.\n",
"- Parse the JSON response into a pandas DataFrame.\n",
"- Visualize token usage over time using matplotlib.\n",
"- Use grouping by model to analyze token usage across different models.\n",
"- Display model distribution with a pie chart.\n",
"\n",
"We also include placeholders for all possible API parameters for a comprehensive overview."
]
},
{
"cell_type": "code",
2025-02-11 09:28:49 -08:00
"execution_count": 1,
2025-01-15 15:39:19 +00:00
"metadata": {},
"outputs": [],
"source": [
"# Install required libraries (if not already installed)\n",
"!pip install requests pandas numpy matplotlib --quiet\n",
"\n",
"# Import libraries\n",
"import requests\n",
"import pandas as pd\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.patches as mpatches\n",
"import time\n",
"import json\n",
"\n",
"# For inline plotting in Jupyter\n",
2025-02-11 09:28:49 -08:00
"%matplotlib inline"
2025-01-15 15:39:19 +00:00
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setup API Credentials and Parameters\n",
"\n",
"Set up an Admin Key - https://platform.openai.com/settings/organization/admin-keys\n",
"\n",
2025-02-11 09:28:49 -08:00
"Replace `'PLACEHOLDER'` with your actual ADMIN API key. It's best practice to load the key from an environment variable for security."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Reusable function for retrieving paginated data from the API\n",
"def get_data(url, params):\n",
" # Set up the API key and headers\n",
" OPENAI_ADMIN_KEY = 'PLACEHOLDER'\n",
"\n",
" headers = {\n",
" \"Authorization\": f\"Bearer {OPENAI_ADMIN_KEY}\",\n",
" \"Content-Type\": \"application/json\",\n",
" }\n",
"\n",
" # Initialize an empty list to store all data\n",
" all_data = []\n",
"\n",
" # Initialize pagination cursor\n",
" page_cursor = None\n",
"\n",
" # Loop to handle pagination\n",
" while True:\n",
" if page_cursor:\n",
" params[\"page\"] = page_cursor\n",
"\n",
" response = requests.get(url, headers=headers, params=params)\n",
"\n",
" if response.status_code == 200:\n",
" data_json = response.json()\n",
" all_data.extend(data_json.get(\"data\", []))\n",
"\n",
" page_cursor = data_json.get(\"next_page\")\n",
" if not page_cursor:\n",
" break\n",
" else:\n",
" print(f\"Error: {response.status_code}\")\n",
" break\n",
"\n",
" if all_data:\n",
" print(\"Data retrieved successfully!\")\n",
" else:\n",
" print(\"Issue: No data available to retrieve.\")\n",
" return all_data"
2025-01-15 15:39:19 +00:00
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Data retrieved successfully!\n"
]
}
],
"source": [
"# Define the API endpoint\n",
"url = \"https://api.openai.com/v1/organization/usage/completions\"\n",
"\n",
"# Calculate start time: n days ago from now\n",
"days_ago = 30\n",
"start_time = int(time.time()) - (days_ago * 24 * 60 * 60)\n",
"\n",
"# Define parameters with placeholders for all possible options\n",
"params = {\n",
" \"start_time\": start_time, # Required: Start time (Unix seconds)\n",
" # \"end_time\": end_time, # Optional: End time (Unix seconds)\n",
2025-02-11 09:28:49 -08:00
" \"bucket_width\": \"1d\", # Optional: '1m', '1h', or '1d' (default '1d')\n",
2025-01-15 15:39:19 +00:00
" # \"project_ids\": [\"proj_example\"], # Optional: List of project IDs\n",
" # \"user_ids\": [\"user_example\"], # Optional: List of user IDs\n",
" # \"api_key_ids\": [\"key_example\"], # Optional: List of API key IDs\n",
2025-02-11 09:28:49 -08:00
" # \"models\": [\"o1-2024-12-17\", \"gpt-4o-2024-08-06\", \"gpt-4o-mini-2024-07-18\"], # Optional: List of models\n",
2025-01-15 15:39:19 +00:00
" # \"batch\": False, # Optional: True for batch jobs, False for non-batch\n",
" # \"group_by\": [\"model\"], # Optional: Fields to group by\n",
2025-02-11 09:28:49 -08:00
" \"limit\": 7, # Optional: Number of buckets to return, this will chunk the data into 7 buckets\n",
2025-01-15 15:39:19 +00:00
" # \"page\": \"cursor_string\" # Optional: Cursor for pagination\n",
"}\n",
"\n",
2025-02-11 09:28:49 -08:00
"usage_data = get_data(url, params)"
2025-01-15 15:39:19 +00:00
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Inspect the JSON Response\n",
"\n",
"Let's take a look at the raw JSON response from the API to understand its structure.\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1736616660,\n",
" \"end_time\": 1736640000,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 141201,\n",
" \"output_tokens\": 9756,\n",
" \"num_model_requests\": 470,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
2025-02-11 09:28:49 -08:00
" \"input_cached_tokens\": 0,\n",
2025-01-15 15:39:19 +00:00
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1736640000,\n",
" \"end_time\": 1736726400,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 45949,\n",
" \"output_tokens\": 282,\n",
" \"num_model_requests\": 150,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
" \"input_cached_tokens\": 0,\n",
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1736726400,\n",
" \"end_time\": 1736812800,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 3718360,\n",
" \"output_tokens\": 97756,\n",
" \"num_model_requests\": 3053,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
2025-02-11 09:28:49 -08:00
" \"input_cached_tokens\": 76544,\n",
" \"input_audio_tokens\": 5776,\n",
" \"output_audio_tokens\": 3166\n",
2025-01-15 15:39:19 +00:00
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1736812800,\n",
" \"end_time\": 1736899200,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 52786,\n",
" \"output_tokens\": 38204,\n",
" \"num_model_requests\": 157,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
2025-02-11 09:28:49 -08:00
" \"input_cached_tokens\": 5440,\n",
" \"input_audio_tokens\": 4066,\n",
" \"output_audio_tokens\": 1097\n",
2025-01-15 15:39:19 +00:00
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1736899200,\n",
" \"end_time\": 1736985600,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 35664,\n",
" \"output_tokens\": 1835,\n",
" \"num_model_requests\": 55,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
2025-02-11 09:28:49 -08:00
" \"input_cached_tokens\": 192,\n",
" \"input_audio_tokens\": 2520,\n",
" \"output_audio_tokens\": 1549\n",
2025-01-15 15:39:19 +00:00
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1736985600,\n",
" \"end_time\": 1737072000,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 5464,\n",
" \"output_tokens\": 2667,\n",
" \"num_model_requests\": 8,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
2025-02-11 09:28:49 -08:00
" \"input_cached_tokens\": 0,\n",
2025-01-15 15:39:19 +00:00
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1737072000,\n",
" \"end_time\": 1737158400,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
" \"input_tokens\": 3390547,\n",
" \"output_tokens\": 38604,\n",
" \"num_model_requests\": 2687,\n",
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
" \"input_cached_tokens\": 25344,\n",
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
" }\n",
" ]\n",
2025-01-15 15:39:19 +00:00
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1737158400,\n",
" \"end_time\": 1737244800,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
" \"input_tokens\": 8117824,\n",
" \"output_tokens\": 105662,\n",
" \"num_model_requests\": 6335,\n",
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
" \"input_cached_tokens\": 46464,\n",
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
" }\n",
" ]\n",
2025-01-15 15:39:19 +00:00
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1737244800,\n",
" \"end_time\": 1737331200,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 13542,\n",
" \"output_tokens\": 85,\n",
" \"num_model_requests\": 46,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
" \"input_cached_tokens\": 0,\n",
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1737331200,\n",
" \"end_time\": 1737417600,\n",
" \"results\": []\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1737417600,\n",
" \"end_time\": 1737504000,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 29806,\n",
" \"output_tokens\": 57604,\n",
" \"num_model_requests\": 98,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
" \"input_cached_tokens\": 0,\n",
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1737504000,\n",
" \"end_time\": 1737590400,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 1823,\n",
" \"output_tokens\": 1467,\n",
" \"num_model_requests\": 7,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
" \"input_cached_tokens\": 0,\n",
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1737590400,\n",
" \"end_time\": 1737676800,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 7126,\n",
" \"output_tokens\": 1896,\n",
" \"num_model_requests\": 19,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
" \"input_cached_tokens\": 0,\n",
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1737676800,\n",
" \"end_time\": 1737763200,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 22187,\n",
" \"output_tokens\": 822,\n",
" \"num_model_requests\": 75,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
2025-02-11 09:28:49 -08:00
" \"input_cached_tokens\": 640,\n",
" \"input_audio_tokens\": 2557,\n",
" \"output_audio_tokens\": 3103\n",
2025-01-15 15:39:19 +00:00
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1737763200,\n",
" \"end_time\": 1737849600,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 30204,\n",
" \"output_tokens\": 65673,\n",
" \"num_model_requests\": 99,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
" \"input_cached_tokens\": 0,\n",
2025-02-11 09:28:49 -08:00
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
2025-01-15 15:39:19 +00:00
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1737849600,\n",
" \"end_time\": 1737936000,\n",
" \"results\": []\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1737936000,\n",
" \"end_time\": 1738022400,\n",
" \"results\": []\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1738022400,\n",
" \"end_time\": 1738108800,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 2541,\n",
" \"output_tokens\": 1604,\n",
" \"num_model_requests\": 14,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
" \"input_cached_tokens\": 0,\n",
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1738108800,\n",
" \"end_time\": 1738195200,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
" \"input_tokens\": 68339,\n",
" \"output_tokens\": 49525,\n",
" \"num_model_requests\": 217,\n",
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
" \"input_cached_tokens\": 7296,\n",
" \"input_audio_tokens\": 20033,\n",
" \"output_audio_tokens\": 3168\n",
" }\n",
" ]\n",
2025-01-15 15:39:19 +00:00
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1738195200,\n",
" \"end_time\": 1738281600,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 18481,\n",
" \"output_tokens\": 17500,\n",
" \"num_model_requests\": 84,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
2025-02-11 09:28:49 -08:00
" \"input_cached_tokens\": 2944,\n",
" \"input_audio_tokens\": 10076,\n",
" \"output_audio_tokens\": 4966\n",
2025-01-15 15:39:19 +00:00
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1738281600,\n",
" \"end_time\": 1738368000,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 1187894,\n",
" \"output_tokens\": 139134,\n",
" \"num_model_requests\": 5528,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
2025-02-11 09:28:49 -08:00
" \"input_cached_tokens\": 2112,\n",
" \"input_audio_tokens\": 4935,\n",
" \"output_audio_tokens\": 993\n",
2025-01-15 15:39:19 +00:00
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1738368000,\n",
" \"end_time\": 1738454400,\n",
" \"results\": []\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1738454400,\n",
" \"end_time\": 1738540800,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 7268,\n",
" \"output_tokens\": 30563,\n",
" \"num_model_requests\": 24,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
" \"input_cached_tokens\": 0,\n",
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1738540800,\n",
" \"end_time\": 1738627200,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 15121,\n",
" \"output_tokens\": 22866,\n",
" \"num_model_requests\": 48,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
2025-02-11 09:28:49 -08:00
" \"input_cached_tokens\": 0,\n",
2025-01-15 15:39:19 +00:00
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1738627200,\n",
" \"end_time\": 1738713600,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 16735,\n",
" \"output_tokens\": 16177,\n",
" \"num_model_requests\": 50,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
2025-02-11 09:28:49 -08:00
" \"input_cached_tokens\": 1152,\n",
2025-01-15 15:39:19 +00:00
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1738713600,\n",
" \"end_time\": 1738800000,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 6573,\n",
" \"output_tokens\": 4238,\n",
" \"num_model_requests\": 43,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
" \"input_cached_tokens\": 0,\n",
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1738800000,\n",
" \"end_time\": 1738886400,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 1402,\n",
" \"output_tokens\": 2042,\n",
" \"num_model_requests\": 18,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
" \"input_cached_tokens\": 0,\n",
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1738886400,\n",
" \"end_time\": 1738972800,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 11847,\n",
" \"output_tokens\": 21938,\n",
" \"num_model_requests\": 47,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
2025-02-11 09:28:49 -08:00
" \"input_cached_tokens\": 0,\n",
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
2025-01-15 15:39:19 +00:00
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1738972800,\n",
" \"end_time\": 1739059200,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 1993,\n",
" \"output_tokens\": 12,\n",
" \"num_model_requests\": 7,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
2025-02-11 09:28:49 -08:00
" \"input_cached_tokens\": 0,\n",
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
2025-01-15 15:39:19 +00:00
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": 1739059200,\n",
" \"end_time\": 1739145600,\n",
" \"results\": []\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1739145600,\n",
" \"end_time\": 1739208663,\n",
2025-01-15 15:39:19 +00:00
" \"results\": [\n",
" {\n",
" \"object\": \"organization.usage.completions.result\",\n",
2025-02-11 09:28:49 -08:00
" \"input_tokens\": 332,\n",
" \"output_tokens\": 1509,\n",
" \"num_model_requests\": 8,\n",
2025-01-15 15:39:19 +00:00
" \"project_id\": null,\n",
" \"user_id\": null,\n",
" \"api_key_id\": null,\n",
" \"model\": null,\n",
" \"batch\": null,\n",
2025-02-11 09:28:49 -08:00
" \"input_cached_tokens\": 0,\n",
" \"input_audio_tokens\": 0,\n",
" \"output_audio_tokens\": 0\n",
2025-01-15 15:39:19 +00:00
" }\n",
" ]\n",
" }\n",
"]\n"
]
}
],
"source": [
2025-02-11 09:28:49 -08:00
"print(json.dumps(usage_data, indent=2))"
2025-01-15 15:39:19 +00:00
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Parse the API Response and Create a DataFrame\n",
"\n",
"Now we will parse the JSON data, extract relevant fields, and create a pandas DataFrame for easier manipulation and analysis."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>start_datetime</th>\n",
" <th>end_datetime</th>\n",
" <th>start_time</th>\n",
" <th>end_time</th>\n",
" <th>input_tokens</th>\n",
" <th>output_tokens</th>\n",
" <th>input_cached_tokens</th>\n",
" <th>input_audio_tokens</th>\n",
" <th>output_audio_tokens</th>\n",
" <th>num_model_requests</th>\n",
" <th>project_id</th>\n",
" <th>user_id</th>\n",
" <th>api_key_id</th>\n",
" <th>model</th>\n",
" <th>batch</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
2025-02-11 09:28:49 -08:00
" <td>2025-01-11 17:31:00</td>\n",
" <td>2025-01-12</td>\n",
" <td>1736616660</td>\n",
" <td>1736640000</td>\n",
" <td>141201</td>\n",
" <td>9756</td>\n",
2025-01-15 15:39:19 +00:00
" <td>0</td>\n",
" <td>0</td>\n",
2025-02-11 09:28:49 -08:00
" <td>0</td>\n",
" <td>470</td>\n",
2025-01-15 15:39:19 +00:00
" <td>None</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
2025-02-11 09:28:49 -08:00
" <td>2025-01-12 00:00:00</td>\n",
" <td>2025-01-13</td>\n",
" <td>1736640000</td>\n",
" <td>1736726400</td>\n",
" <td>45949</td>\n",
" <td>282</td>\n",
2025-01-15 15:39:19 +00:00
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
2025-02-11 09:28:49 -08:00
" <td>150</td>\n",
2025-01-15 15:39:19 +00:00
" <td>None</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
2025-02-11 09:28:49 -08:00
" <td>2025-01-13 00:00:00</td>\n",
" <td>2025-01-14</td>\n",
" <td>1736726400</td>\n",
" <td>1736812800</td>\n",
" <td>3718360</td>\n",
" <td>97756</td>\n",
" <td>76544</td>\n",
" <td>5776</td>\n",
" <td>3166</td>\n",
" <td>3053</td>\n",
2025-01-15 15:39:19 +00:00
" <td>None</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
2025-02-11 09:28:49 -08:00
" <td>2025-01-14 00:00:00</td>\n",
" <td>2025-01-15</td>\n",
" <td>1736812800</td>\n",
" <td>1736899200</td>\n",
" <td>52786</td>\n",
" <td>38204</td>\n",
" <td>5440</td>\n",
" <td>4066</td>\n",
" <td>1097</td>\n",
" <td>157</td>\n",
2025-01-15 15:39:19 +00:00
" <td>None</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
2025-02-11 09:28:49 -08:00
" <td>2025-01-15 00:00:00</td>\n",
" <td>2025-01-16</td>\n",
" <td>1736899200</td>\n",
" <td>1736985600</td>\n",
" <td>35664</td>\n",
" <td>1835</td>\n",
" <td>192</td>\n",
" <td>2520</td>\n",
" <td>1549</td>\n",
" <td>55</td>\n",
2025-01-15 15:39:19 +00:00
" <td>None</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" start_datetime end_datetime start_time end_time input_tokens \\\n",
2025-02-11 09:28:49 -08:00
"0 2025-01-11 17:31:00 2025-01-12 1736616660 1736640000 141201 \n",
"1 2025-01-12 00:00:00 2025-01-13 1736640000 1736726400 45949 \n",
"2 2025-01-13 00:00:00 2025-01-14 1736726400 1736812800 3718360 \n",
"3 2025-01-14 00:00:00 2025-01-15 1736812800 1736899200 52786 \n",
"4 2025-01-15 00:00:00 2025-01-16 1736899200 1736985600 35664 \n",
2025-01-15 15:39:19 +00:00
"\n",
" output_tokens input_cached_tokens input_audio_tokens \\\n",
2025-02-11 09:28:49 -08:00
"0 9756 0 0 \n",
"1 282 0 0 \n",
"2 97756 76544 5776 \n",
"3 38204 5440 4066 \n",
"4 1835 192 2520 \n",
2025-01-15 15:39:19 +00:00
"\n",
" output_audio_tokens num_model_requests project_id user_id api_key_id \\\n",
2025-02-11 09:28:49 -08:00
"0 0 470 None None None \n",
"1 0 150 None None None \n",
"2 3166 3053 None None None \n",
"3 1097 157 None None None \n",
"4 1549 55 None None None \n",
2025-01-15 15:39:19 +00:00
"\n",
2025-02-11 09:28:49 -08:00
" model batch \n",
"0 None None \n",
"1 None None \n",
"2 None None \n",
"3 None None \n",
"4 None None "
2025-01-15 15:39:19 +00:00
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Initialize a list to hold parsed records\n",
"records = []\n",
"\n",
"# Iterate through the data to extract bucketed data\n",
2025-02-11 09:28:49 -08:00
"for bucket in usage_data:\n",
2025-01-15 15:39:19 +00:00
" start_time = bucket.get(\"start_time\")\n",
" end_time = bucket.get(\"end_time\")\n",
" for result in bucket.get(\"results\", []):\n",
2025-02-11 09:28:49 -08:00
" records.append(\n",
" {\n",
" \"start_time\": start_time,\n",
" \"end_time\": end_time,\n",
" \"input_tokens\": result.get(\"input_tokens\", 0),\n",
" \"output_tokens\": result.get(\"output_tokens\", 0),\n",
" \"input_cached_tokens\": result.get(\"input_cached_tokens\", 0),\n",
" \"input_audio_tokens\": result.get(\"input_audio_tokens\", 0),\n",
" \"output_audio_tokens\": result.get(\"output_audio_tokens\", 0),\n",
" \"num_model_requests\": result.get(\"num_model_requests\", 0),\n",
" \"project_id\": result.get(\"project_id\"),\n",
" \"user_id\": result.get(\"user_id\"),\n",
" \"api_key_id\": result.get(\"api_key_id\"),\n",
" \"model\": result.get(\"model\"),\n",
" \"batch\": result.get(\"batch\"),\n",
" }\n",
" )\n",
2025-01-15 15:39:19 +00:00
"\n",
"# Create a DataFrame from the records\n",
"df = pd.DataFrame(records)\n",
"\n",
"# Convert Unix timestamps to datetime for readability\n",
2025-02-11 09:28:49 -08:00
"df[\"start_datetime\"] = pd.to_datetime(df[\"start_time\"], unit=\"s\")\n",
"df[\"end_datetime\"] = pd.to_datetime(df[\"end_time\"], unit=\"s\")\n",
2025-01-15 15:39:19 +00:00
"\n",
"# Reorder columns for better readability\n",
"df = df[\n",
" [\n",
2025-02-11 09:28:49 -08:00
" \"start_datetime\",\n",
" \"end_datetime\",\n",
" \"start_time\",\n",
" \"end_time\",\n",
" \"input_tokens\",\n",
" \"output_tokens\",\n",
" \"input_cached_tokens\",\n",
" \"input_audio_tokens\",\n",
" \"output_audio_tokens\",\n",
" \"num_model_requests\",\n",
" \"project_id\",\n",
" \"user_id\",\n",
" \"api_key_id\",\n",
" \"model\",\n",
" \"batch\",\n",
2025-01-15 15:39:19 +00:00
" ]\n",
"]\n",
"\n",
"# Display the DataFrame\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Visualize Token Usage Over Time\n",
"\n",
"We'll create a bar chart to visualize input and output token usage for each time bucket.\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
2025-02-11 09:28:49 -08:00
"image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAJOCAYAAABm7rQwAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAACLd0lEQVR4nOzdZ3gU5fv28XOTkFATegmELr1XAQWkiAgIovSfFFFAURBEEVGqgFhRURQLoNJsIIpSRAGlg9KkQ+i9JdQQkut5wZP9syRIFpLZEL6f49gD9p7ZmXNnZye7195zj8vMTAAAAAAAAICD/HwdAAAAAAAAAHceilIAAAAAAABwHEUpAAAAAAAAOI6iFAAAAAAAABxHUQoAAAAAAACOoygFAAAAAAAAx1GUAgAAAAAAgOMoSgEAAAAAAMBxFKUAAAAAAADgOIpSAIBUZeLEiXK5XNq9e7e7rW7duqpbt67PMgHeKFiwoJo2berrGAAAAMmOohQAwHFxhaO4W9q0aRUaGqpGjRrp/fff15kzZ3wd8T+5XC4988wzvo7hNmXKFI0ZM8bXMTycO3dOw4cPV7ly5ZQ+fXqFhITo3nvv1Zdffikzu+nl/vLLLxoyZEjSBf0P58+f15AhQ7Rw4cIbzluwYEGPffp6t4kTJyZ77qRUt25dlSlTJsFpx48fl8vlcuz1SC5DhgyRy+XS8ePHHVnf0qVLNWTIEJ0+fTpR88+YMUONGjVSaGiogoKClC9fPj366KPauHFjgvPPmjVLlSpVUtq0aZU/f34NHjxYly9fvuF6Fi5c6LGvBgUFKVeuXKpbt65GjhypY8eOefM0AQBIlABfBwAA3LmGDRumQoUKKTo6WocPH9bChQv13HPP6Z133tGsWbNUrlw5r5f52GOPqW3btgoKCkqGxCnTlClTtHHjRj333HO+jiJJOnLkiOrXr6/Nmzerbdu2euaZZ3Tx4kV9//336tSpk3755RdNnjxZ/v7+Xi/7l19+0YcffuhIIeT8+fMaOnSoJN2wp92YMWN09uxZ9/1ffvlFU6dO1bvvvqvs2bO722vWrJksWXH7WLp0qYYOHarOnTsrc+bMN5x/w4YNypIli3r37q3s2bPr8OHD+uKLL1StWjUtW7ZM5cuXd8/766+/qkWLFqpbt64++OADbdiwQa+99pqOHj2qcePGJSpfr169VLVqVcXExOjYsWNaunSpBg8erHfeeUfffPON6tWrd7NPHQCAeChKAQB8pnHjxqpSpYr7/oABA/T777+radOmeuihh7R582alS5fOq2X6+/vfVLEDSadTp07avHmzZsyYoYceesjd3qtXL73wwgt66623VLFiRfXv39+HKZNWixYtPO4fPnxYU6dOVYsWLVSwYEGfZELqMGjQoHhtTzzxhPLly6dx48bp448/drf369dP5cqV07x58xQQcOVjfnBwsEaOHKnevXurRIkSN1zfvffeq0cffdSjbd26dbr//vv1yCOPaNOmTcqTJ88tPisAAK7g9D0AQIpSr149vfrqq9qzZ4++/vprd/v69evVuXNnFS5cWGnTplXu3Ln1+OOP68SJEx6PT2hMqaudPXtWGTJkUO/eveNN279/v/z9/TVq1CivMsed9vLNN99oxIgRypcvn9KmTav69etrx44dHvPGnQ61Zs0a1axZU+nSpVOhQoU8vlj+1/OIW1fcKWV169bV7NmztWfPHvdpN/9VBClTpozuu+++eO2xsbHKmzevx5fRadOmqXLlysqUKZOCg4NVtmxZvffee/+5LZYvX665c+eqc+fOHgWpOKNGjdJdd92l0aNH68KFCwk+pzi7d+/2OOWtc+fO+vDDDyXJ4zSjq+d966239O6776pAgQJKly6d6tSpE+80p+uNMda5c2f3ttu9e7dy5MghSRo6dKh7XbfSQ+vy5csaPny4ihQpoqCgIBUsWFAvv/yyoqKibvjYSZMmKSAgQC+88IK7bcWKFXrggQcUEhKi9OnTq06dOlqyZInH4+JOTduxY4e7Z05ISIi6dOmi8+fP3/RzuZ4zZ87oueeeU8GCBRUUFKScOXOqYcOG+vvvv93z/Pnnn2rVqpXy58+voKAghYWFqU+fPu794WrffvutSpUqpbRp06pMmTKaMWOGx+sUJzY2VmPGjFHp0qWVNm1a5cqVS927d9epU6eS5HmdPHlS/fr1U9myZZUxY0YFBwercePGWrduXbx5P/jgA5UuXVrp06dXlixZVKVKFU2ZMkXSldcj7jUsVKiQe7+63vHqenLmzKn06dN7nAK4adMmbdq0Sd26dXMXpCTp6aeflpnpu+++8/6J/3/ly5fXmDFjdPr0aY0dO9bdvmfPHj399NMqXry40qVLp2zZsqlVq1Yez2fXrl1yuVx699134y136dKlcrlcmjp1qqTE7T8AgNSFnlIAgBTnscce08svv6x58+bpySeflCTNnz9fu3btUpcuXZQ7d279+++/Gj9+vP79918tX77cXZy4kYwZM+rhhx/W9OnT9c4773j0qpo6darMTB06dLip3K+//rr8/PzUr18/RURE6I033lCHDh20YsUKj/lOnTqlBx98UK1bt1a7du30zTff6KmnnlJgYKAef/xxr9Y5cOBARUREaP/+/e4vfRkzZrzu/G3atNGQIUN0+PBh5c6d293+119/6eDBg2rbtq2kK9u7Xbt2ql+/vkaPHi1J2rx5s5YsWZJgQS/OTz/9JEnq2LFjgtMDAgLUvn17DR06VEuWLFGDBg0S/Vy7d++ugwcPav78+frqq68SnOfLL7/UmTNn1LNnT128eFHvvfee6tWrpw0bNihXrlyJXleOHDk0btw4PfXUU3r44YfVsmVLSbqpU0rjPPHEE5o0aZIeffRRPf/881qxYoVGjRrl7lV2PePHj1ePHj308ssv67XXXpMk/f7772rcuLEqV66swYMHy8/PTxMmTFC9evX0559/qlq1ah7LaN26tQoVKqRRo0bp77//1meffaacOXO6X9uk0qNHD3333Xd65plnVKpUKZ04cUJ//fWXNm/erEqVKkm6Umg6f/68nnrqKWXLlk0rV67UBx98oP379+vbb791L2v27Nlq06aNypYtq1GjRunUqVPq2rWr8ubNG2+93bt318SJE9WlSxf16tVL4eHhGjt2rP755x8tWbJEadKkuaXntWvXLs2cOVOtWrVSoUKFdOTIEX3yySeqU6eONm3apNDQUEnSp59+ql69eunRRx9V7969dfHiRa1fv14rVqxQ+/bt1bJlS23bti3eqZ1xBdD/cvr0afepzmPGjFFkZKTq16/vnv7PP/9IkkfvU0kKDQ1Vvnz53NNv1qOPPqquXbtq3rx5GjFihCRp1apVWrp0qdq2bat8+fJp9+7dGjdunOrWratNmzYpffr0Kly4sGrVqqXJkyerT58+HsucPHmyMmXKpObNm0tK3P4DAEhlDAAAh02YMMEk2apVq647T0hIiFWsWNF9//z58/HmmTp1qkmyxYsXx1t2eHi4u61OnTpWp04d9/25c+eaJPv11189lleuXDmP+a5HkvXs2dN9/48//jBJVrJkSYuKinK3v/feeybJNmzY4JFFkr399tvutqioKKtQoYLlzJnTLl26dN3ncfW6/vjjD3dbkyZNrECBAjfMbWa2detWk2QffPCBR/vTTz9tGTNmdG/n3r17W3BwsF2+fDlRy43TokULk2SnTp267jw//PCDSbL333//us/JzCw8PNwk2YQJE9xtPXv2tIQ+vsTNmy5dOtu/f7+7fcWKFSbJ+vTp4267dn+I06lTJ4/teOzYMZNkgwcP/s/nnJA333zT4/Vbu3atSbInnnjCY75+/fqZJPv999/dbQUKFLAmTZqY2ZV9yOVy2fDhw93TY2Nj7a677rJGjRpZbGysu/38+fNWqFAha9iwobtt8ODBJskef/xxj/U+/PDDli1bths+jzp16ljp0qUTnJbQ9gkJCfF4byQkoffyqFGjzOVy2Z49e9xtZcuWtXz58tmZM2fcbQsXLjRJHq/Tn3/+aZJs8uTJHsucM2dOgu3XittGx44
2025-01-15 15:39:19 +00:00
"text/plain": [
"<Figure size 1200x600 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"if not df.empty:\n",
" plt.figure(figsize=(12, 6))\n",
2025-02-11 09:28:49 -08:00
"\n",
2025-01-15 15:39:19 +00:00
" # Create bar charts for input and output tokens\n",
" width = 0.35 # width of the bars\n",
" indices = range(len(df))\n",
2025-02-11 09:28:49 -08:00
"\n",
" plt.bar(indices, df[\"input_tokens\"], width=width, label=\"Input Tokens\", alpha=0.7)\n",
" plt.bar(\n",
" [i + width for i in indices],\n",
" df[\"output_tokens\"],\n",
" width=width,\n",
" label=\"Output Tokens\",\n",
" alpha=0.7,\n",
" )\n",
"\n",
2025-01-15 15:39:19 +00:00
" # Set labels and ticks\n",
2025-02-11 09:28:49 -08:00
" plt.xlabel(\"Time Bucket\")\n",
" plt.ylabel(\"Number of Tokens\")\n",
" plt.title(\"Daily Input vs Output Token Usage Last 30 Days\")\n",
" plt.xticks(\n",
" [i + width / 2 for i in indices],\n",
" [dt.strftime(\"%Y-%m-%d\") for dt in df[\"start_datetime\"]],\n",
" rotation=45,\n",
" )\n",
2025-01-15 15:39:19 +00:00
" plt.legend()\n",
" plt.tight_layout()\n",
" plt.show()\n",
"else:\n",
" print(\"No data available to plot.\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Visual Example: Grouping by Model\n",
"\n",
"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.\n",
"\n",
"### Note on Grouping Parameter\n",
"\n",
"- If you do not specify a `group_by` parameter, fields such as `project_id`, `model`, and others will return as `null`. \n",
" Although the `group_by` parameter is optional, it is recommended to include it in most cases to retrieve meaningful data.\n",
" \n",
"- You can specify multiple group fields by separating them with commas. For example: `group_by=[\"model\", \"project_id\"]`."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Data retrieved successfully!\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>start_datetime</th>\n",
" <th>end_datetime</th>\n",
" <th>start_time</th>\n",
" <th>end_time</th>\n",
" <th>input_tokens</th>\n",
" <th>output_tokens</th>\n",
" <th>input_cached_tokens</th>\n",
" <th>input_audio_tokens</th>\n",
" <th>output_audio_tokens</th>\n",
" <th>num_model_requests</th>\n",
" <th>project_id</th>\n",
" <th>user_id</th>\n",
" <th>api_key_id</th>\n",
" <th>model</th>\n",
" <th>batch</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
2025-02-11 09:28:49 -08:00
" <td>2025-01-11 17:31:39</td>\n",
" <td>2025-01-12</td>\n",
" <td>1736616699</td>\n",
" <td>1736640000</td>\n",
" <td>6897</td>\n",
" <td>97</td>\n",
2025-01-15 15:39:19 +00:00
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
2025-02-11 09:28:49 -08:00
" <td>97</td>\n",
" <td>proj_hNhhQzyYu7HxySZWs7cA3Ugu</td>\n",
2025-01-15 15:39:19 +00:00
" <td>None</td>\n",
" <td>None</td>\n",
2025-02-11 09:28:49 -08:00
" <td>gpt-4o-mini-2024-07-18</td>\n",
2025-01-15 15:39:19 +00:00
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
2025-02-11 09:28:49 -08:00
" <td>2025-01-11 17:31:39</td>\n",
" <td>2025-01-12</td>\n",
" <td>1736616699</td>\n",
" <td>1736640000</td>\n",
" <td>33984</td>\n",
" <td>206</td>\n",
2025-01-15 15:39:19 +00:00
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
2025-02-11 09:28:49 -08:00
" <td>95</td>\n",
" <td>proj_hNhhQzyYu7HxySZWs7cA3Ugu</td>\n",
2025-01-15 15:39:19 +00:00
" <td>None</td>\n",
" <td>None</td>\n",
2025-02-11 09:28:49 -08:00
" <td>ft:gpt-4o-2024-08-06:distillation-test:wordle2...</td>\n",
2025-01-15 15:39:19 +00:00
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
2025-02-11 09:28:49 -08:00
" <td>2025-01-11 17:31:39</td>\n",
" <td>2025-01-12</td>\n",
" <td>1736616699</td>\n",
" <td>1736640000</td>\n",
" <td>2846</td>\n",
" <td>8874</td>\n",
2025-01-15 15:39:19 +00:00
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
2025-02-11 09:28:49 -08:00
" <td>8</td>\n",
" <td>proj_hNhhQzyYu7HxySZWs7cA3Ugu</td>\n",
2025-01-15 15:39:19 +00:00
" <td>None</td>\n",
" <td>None</td>\n",
2025-02-11 09:28:49 -08:00
" <td>o1-mini-2024-09-12</td>\n",
2025-01-15 15:39:19 +00:00
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
2025-02-11 09:28:49 -08:00
" <td>2025-01-11 17:31:39</td>\n",
" <td>2025-01-12</td>\n",
" <td>1736616699</td>\n",
" <td>1736640000</td>\n",
" <td>97474</td>\n",
" <td>579</td>\n",
2025-01-15 15:39:19 +00:00
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
2025-02-11 09:28:49 -08:00
" <td>270</td>\n",
" <td>proj_hNhhQzyYu7HxySZWs7cA3Ugu</td>\n",
2025-01-15 15:39:19 +00:00
" <td>None</td>\n",
" <td>None</td>\n",
" <td>gpt-4o-2024-08-06</td>\n",
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
2025-02-11 09:28:49 -08:00
" <td>2025-01-12 00:00:00</td>\n",
" <td>2025-01-13</td>\n",
" <td>1736640000</td>\n",
" <td>1736726400</td>\n",
" <td>1989</td>\n",
" <td>28</td>\n",
2025-01-15 15:39:19 +00:00
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
2025-02-11 09:28:49 -08:00
" <td>28</td>\n",
" <td>proj_hNhhQzyYu7HxySZWs7cA3Ugu</td>\n",
2025-01-15 15:39:19 +00:00
" <td>None</td>\n",
" <td>None</td>\n",
2025-02-11 09:28:49 -08:00
" <td>gpt-4o-mini-2024-07-18</td>\n",
2025-01-15 15:39:19 +00:00
" <td>None</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" start_datetime end_datetime start_time end_time input_tokens \\\n",
2025-02-11 09:28:49 -08:00
"0 2025-01-11 17:31:39 2025-01-12 1736616699 1736640000 6897 \n",
"1 2025-01-11 17:31:39 2025-01-12 1736616699 1736640000 33984 \n",
"2 2025-01-11 17:31:39 2025-01-12 1736616699 1736640000 2846 \n",
"3 2025-01-11 17:31:39 2025-01-12 1736616699 1736640000 97474 \n",
"4 2025-01-12 00:00:00 2025-01-13 1736640000 1736726400 1989 \n",
2025-01-15 15:39:19 +00:00
"\n",
" output_tokens input_cached_tokens input_audio_tokens \\\n",
2025-02-11 09:28:49 -08:00
"0 97 0 0 \n",
"1 206 0 0 \n",
"2 8874 0 0 \n",
"3 579 0 0 \n",
"4 28 0 0 \n",
2025-01-15 15:39:19 +00:00
"\n",
" output_audio_tokens num_model_requests project_id \\\n",
2025-02-11 09:28:49 -08:00
"0 0 97 proj_hNhhQzyYu7HxySZWs7cA3Ugu \n",
"1 0 95 proj_hNhhQzyYu7HxySZWs7cA3Ugu \n",
"2 0 8 proj_hNhhQzyYu7HxySZWs7cA3Ugu \n",
"3 0 270 proj_hNhhQzyYu7HxySZWs7cA3Ugu \n",
"4 0 28 proj_hNhhQzyYu7HxySZWs7cA3Ugu \n",
2025-01-15 15:39:19 +00:00
"\n",
2025-02-11 09:28:49 -08:00
" user_id api_key_id model batch \n",
"0 None None gpt-4o-mini-2024-07-18 None \n",
"1 None None ft:gpt-4o-2024-08-06:distillation-test:wordle2... None \n",
"2 None None o1-mini-2024-09-12 None \n",
"3 None None gpt-4o-2024-08-06 None \n",
"4 None None gpt-4o-mini-2024-07-18 None "
2025-01-15 15:39:19 +00:00
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Calculate start time: n days ago from now\n",
"days_ago = 30\n",
"start_time = int(time.time()) - (days_ago * 24 * 60 * 60)\n",
"\n",
"# Define parameters with grouping by model and project_id\n",
"params = {\n",
2025-02-11 09:28:49 -08:00
" \"start_time\": start_time, # Required: Start time (Unix seconds)\n",
" \"bucket_width\": \"1d\", # Optional: '1m', '1h', or '1d' (default '1d')\n",
2025-01-15 15:39:19 +00:00
" \"group_by\": [\"model\", \"project_id\"], # Group data by model and project_id\n",
2025-02-11 09:28:49 -08:00
" \"limit\": 7, # Optional: Number of buckets to return\n",
2025-01-15 15:39:19 +00:00
"}\n",
"\n",
"# Initialize an empty list to store all data\n",
2025-02-11 09:28:49 -08:00
"all_group_data = get_data(url, params)\n",
2025-01-15 15:39:19 +00:00
"\n",
"# Initialize a list to hold parsed records\n",
"records = []\n",
"\n",
"# Iterate through the data to extract bucketed data\n",
"for bucket in all_group_data:\n",
" start_time = bucket.get(\"start_time\")\n",
" end_time = bucket.get(\"end_time\")\n",
" for result in bucket.get(\"results\", []):\n",
2025-02-11 09:28:49 -08:00
" records.append(\n",
" {\n",
" \"start_time\": start_time,\n",
" \"end_time\": end_time,\n",
" \"input_tokens\": result.get(\"input_tokens\", 0),\n",
" \"output_tokens\": result.get(\"output_tokens\", 0),\n",
" \"input_cached_tokens\": result.get(\"input_cached_tokens\", 0),\n",
" \"input_audio_tokens\": result.get(\"input_audio_tokens\", 0),\n",
" \"output_audio_tokens\": result.get(\"output_audio_tokens\", 0),\n",
" \"num_model_requests\": result.get(\"num_model_requests\", 0),\n",
" \"project_id\": result.get(\"project_id\", \"N/A\"),\n",
" \"user_id\": result.get(\"user_id\", \"N/A\"),\n",
" \"api_key_id\": result.get(\"api_key_id\", \"N/A\"),\n",
" \"model\": result.get(\"model\", \"N/A\"),\n",
" \"batch\": result.get(\"batch\", \"N/A\"),\n",
" }\n",
" )\n",
2025-01-15 15:39:19 +00:00
"\n",
"# Create a DataFrame from the records\n",
"df = pd.DataFrame(records)\n",
"\n",
"# Convert Unix timestamps to datetime for readability\n",
2025-02-11 09:28:49 -08:00
"df[\"start_datetime\"] = pd.to_datetime(df[\"start_time\"], unit=\"s\", errors=\"coerce\")\n",
"df[\"end_datetime\"] = pd.to_datetime(df[\"end_time\"], unit=\"s\", errors=\"coerce\")\n",
2025-01-15 15:39:19 +00:00
"\n",
"# Reorder columns for better readability\n",
"df = df[\n",
" [\n",
2025-02-11 09:28:49 -08:00
" \"start_datetime\",\n",
" \"end_datetime\",\n",
" \"start_time\",\n",
" \"end_time\",\n",
" \"input_tokens\",\n",
" \"output_tokens\",\n",
" \"input_cached_tokens\",\n",
" \"input_audio_tokens\",\n",
" \"output_audio_tokens\",\n",
" \"num_model_requests\",\n",
" \"project_id\",\n",
" \"user_id\",\n",
" \"api_key_id\",\n",
" \"model\",\n",
" \"batch\",\n",
2025-01-15 15:39:19 +00:00
" ]\n",
"]\n",
"\n",
"# Display the DataFrame\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Parse the API Response into DataFrame and render a stacked bar chart\n",
"\n",
"Now we will parse the JSON data, extract relevant fields, and create a pandas DataFrame for easier manipulation and analysis."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
2025-02-11 09:28:49 -08:00
"image/png": "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
2025-01-15 15:39:19 +00:00
"text/plain": [
"<Figure size 1200x600 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Group data by model and project_id and aggregate model request counts\n",
"grouped_by_model_project = (\n",
" df.groupby([\"model\", \"project_id\"])\n",
2025-02-11 09:28:49 -08:00
" .agg(\n",
" {\n",
" \"num_model_requests\": \"sum\",\n",
" }\n",
" )\n",
2025-01-15 15:39:19 +00:00
" .reset_index()\n",
")\n",
"\n",
"# Determine unique models and project IDs for plotting and color mapping\n",
2025-02-11 09:28:49 -08:00
"models = sorted(grouped_by_model_project[\"model\"].unique())\n",
"project_ids = sorted(grouped_by_model_project[\"project_id\"].unique())\n",
2025-01-15 15:39:19 +00:00
"distinct_colors = [\n",
2025-02-11 09:28:49 -08:00
" \"#1f77b4\",\n",
" \"#ff7f0e\",\n",
" \"#2ca02c\",\n",
" \"#d62728\",\n",
" \"#9467bd\",\n",
" \"#8c564b\",\n",
" \"#e377c2\",\n",
" \"#7f7f7f\",\n",
" \"#bcbd22\",\n",
" \"#17becf\",\n",
2025-01-15 15:39:19 +00:00
"]\n",
2025-02-11 09:28:49 -08:00
"project_color_mapping = {\n",
" pid: distinct_colors[i % len(distinct_colors)] for i, pid in enumerate(project_ids)\n",
"}\n",
2025-01-15 15:39:19 +00:00
"\n",
"# Calculate total number of requests per project_id for legend\n",
"project_totals = (\n",
2025-02-11 09:28:49 -08:00
" grouped_by_model_project.groupby(\"project_id\")[\"num_model_requests\"]\n",
" .sum()\n",
2025-01-15 15:39:19 +00:00
" .sort_values(ascending=False) # Sort by highest total first\n",
")\n",
"\n",
"# Set up bar positions\n",
"n_models = len(models)\n",
"bar_width = 0.6\n",
"x = np.arange(n_models)\n",
"\n",
"plt.figure(figsize=(12, 6))\n",
"\n",
"# Plot stacked bars for each model\n",
"for model_idx, model in enumerate(models):\n",
" # Filter data for the current model\n",
2025-02-11 09:28:49 -08:00
" model_data = grouped_by_model_project[grouped_by_model_project[\"model\"] == model]\n",
"\n",
2025-01-15 15:39:19 +00:00
" bottom = 0\n",
" # Stack segments for each project ID within the bars\n",
" for _, row in model_data.iterrows():\n",
2025-02-11 09:28:49 -08:00
" color = project_color_mapping[row[\"project_id\"]]\n",
" plt.bar(\n",
" x[model_idx],\n",
" row[\"num_model_requests\"],\n",
" width=bar_width,\n",
" bottom=bottom,\n",
" color=color,\n",
" )\n",
" bottom += row[\"num_model_requests\"]\n",
2025-01-15 15:39:19 +00:00
"\n",
"# Labeling and styling\n",
2025-02-11 09:28:49 -08:00
"plt.xlabel(\"Model\")\n",
"plt.ylabel(\"Number of Model Requests\")\n",
"plt.title(\"Total Model Requests by Model and Project ID Last 30 Days\")\n",
2025-01-15 15:39:19 +00:00
"plt.xticks(x, models, rotation=45, ha=\"right\")\n",
"\n",
"# Create a sorted legend with totals\n",
"handles = [\n",
2025-02-11 09:28:49 -08:00
" mpatches.Patch(color=project_color_mapping[pid], label=f\"{pid} (Total: {total})\")\n",
2025-01-15 15:39:19 +00:00
" for pid, total in project_totals.items()\n",
"]\n",
2025-02-11 09:28:49 -08:00
"plt.legend(handles=handles, bbox_to_anchor=(1.05, 1), loc=\"upper left\")\n",
2025-01-15 15:39:19 +00:00
"\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Visual Example: Model Distribution Pie Chart\n",
"\n",
"This section visualizes the distribution of token usage across different models using a pie chart.\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
2025-02-11 09:28:49 -08:00
"image/png": "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
2025-01-15 15:39:19 +00:00
"text/plain": [
"<Figure size 1000x800 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
2025-02-11 09:28:49 -08:00
"image/png": "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
2025-01-15 15:39:19 +00:00
"text/plain": [
"<Figure size 1000x800 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"records = []\n",
"for bucket in all_group_data:\n",
" for result in bucket.get(\"results\", []):\n",
2025-02-11 09:28:49 -08:00
" records.append(\n",
" {\n",
" \"project_id\": result.get(\"project_id\", \"N/A\"),\n",
" \"num_model_requests\": result.get(\"num_model_requests\", 0),\n",
" }\n",
" )\n",
2025-01-15 15:39:19 +00:00
"\n",
"# Create a DataFrame\n",
"df = pd.DataFrame(records)\n",
"\n",
"# Aggregate data by project_id\n",
"grouped_by_project = (\n",
2025-02-11 09:28:49 -08:00
" df.groupby(\"project_id\").agg({\"num_model_requests\": \"sum\"}).reset_index()\n",
2025-01-15 15:39:19 +00:00
")\n",
"\n",
"# Visualize Pie Chart\n",
"if not grouped_by_project.empty:\n",
" # Filter out rows where num_model_requests == 0\n",
2025-02-11 09:28:49 -08:00
" filtered_grouped_by_project = grouped_by_project[\n",
" grouped_by_project[\"num_model_requests\"] > 0\n",
" ]\n",
"\n",
2025-01-15 15:39:19 +00:00
" # Calculate the total model requests after filtering\n",
2025-02-11 09:28:49 -08:00
" total_requests = filtered_grouped_by_project[\"num_model_requests\"].sum()\n",
"\n",
2025-01-15 15:39:19 +00:00
" if total_requests > 0:\n",
" # Calculate percentage of total for each project\n",
2025-02-11 09:28:49 -08:00
" filtered_grouped_by_project[\"percentage\"] = (\n",
" filtered_grouped_by_project[\"num_model_requests\"] / total_requests\n",
2025-01-15 15:39:19 +00:00
" ) * 100\n",
2025-02-11 09:28:49 -08:00
"\n",
2025-01-15 15:39:19 +00:00
" # Separate \"Other\" projects (below 5%)\n",
2025-02-11 09:28:49 -08:00
" other_projects = filtered_grouped_by_project[\n",
" filtered_grouped_by_project[\"percentage\"] < 5\n",
" ]\n",
" main_projects = filtered_grouped_by_project[\n",
" filtered_grouped_by_project[\"percentage\"] >= 5\n",
" ]\n",
"\n",
2025-01-15 15:39:19 +00:00
" # Sum up \"Other\" projects\n",
" if not other_projects.empty:\n",
2025-02-11 09:28:49 -08:00
" other_row = pd.DataFrame(\n",
" {\n",
" \"project_id\": [\"Other\"],\n",
" \"num_model_requests\": [other_projects[\"num_model_requests\"].sum()],\n",
" \"percentage\": [other_projects[\"percentage\"].sum()],\n",
" }\n",
" )\n",
" filtered_grouped_by_project = pd.concat(\n",
" [main_projects, other_row], ignore_index=True\n",
" )\n",
"\n",
2025-01-15 15:39:19 +00:00
" # Sort by number of requests for better legend organization\n",
2025-02-11 09:28:49 -08:00
" filtered_grouped_by_project = filtered_grouped_by_project.sort_values(\n",
" by=\"num_model_requests\", ascending=False\n",
" )\n",
"\n",
2025-01-15 15:39:19 +00:00
" # Main pie chart for distribution of model requests by project_id\n",
" plt.figure(figsize=(10, 8))\n",
" plt.pie(\n",
2025-02-11 09:28:49 -08:00
" filtered_grouped_by_project[\"num_model_requests\"],\n",
" labels=filtered_grouped_by_project[\"project_id\"],\n",
" autopct=lambda p: f\"{p:.1f}%\\n({int(p * total_requests / 100):,})\",\n",
2025-01-15 15:39:19 +00:00
" startangle=140,\n",
2025-02-11 09:28:49 -08:00
" textprops={\"fontsize\": 10},\n",
2025-01-15 15:39:19 +00:00
" )\n",
2025-02-11 09:28:49 -08:00
" plt.title(\"Distribution of Model Requests by Project ID\", fontsize=14)\n",
" plt.axis(\"equal\") # Equal aspect ratio ensures pie chart is circular.\n",
2025-01-15 15:39:19 +00:00
" plt.tight_layout()\n",
" plt.show()\n",
2025-02-11 09:28:49 -08:00
"\n",
2025-01-15 15:39:19 +00:00
" # If there are \"Other\" projects, generate a second pie chart for breakdown\n",
" if not other_projects.empty:\n",
2025-02-11 09:28:49 -08:00
" other_total_requests = other_projects[\"num_model_requests\"].sum()\n",
"\n",
2025-01-15 15:39:19 +00:00
" plt.figure(figsize=(10, 8))\n",
" plt.pie(\n",
2025-02-11 09:28:49 -08:00
" other_projects[\"num_model_requests\"],\n",
" labels=other_projects[\"project_id\"],\n",
" autopct=lambda p: f\"{p:.1f}%\\n({int(p * other_total_requests / 100):,})\",\n",
2025-01-15 15:39:19 +00:00
" startangle=140,\n",
2025-02-11 09:28:49 -08:00
" textprops={\"fontsize\": 10},\n",
2025-01-15 15:39:19 +00:00
" )\n",
" plt.title('Breakdown of \"Other\" Projects by Model Requests', fontsize=14)\n",
2025-02-11 09:28:49 -08:00
" plt.axis(\"equal\") # Equal aspect ratio ensures pie chart is circular.\n",
2025-01-15 15:39:19 +00:00
" plt.tight_layout()\n",
" plt.show()\n",
" else:\n",
" print(\"Total model requests is zero. Pie chart will not be rendered.\")\n",
"else:\n",
" print(\"No grouped data available for pie chart.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Costs API Example\n",
"\n",
"In this section, we'll work with the OpenAI Costs API to retrieve and visualize cost data. Similar to the completions data, we'll:\n",
"- Call the Costs API to get aggregated cost data.\n",
"- Parse the JSON response into a pandas DataFrame.\n",
"- Visualize costs grouped by line item using a bar chart."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
2025-02-11 09:28:49 -08:00
"Data retrieved successfully!\n"
2025-01-15 15:39:19 +00:00
]
}
],
"source": [
"# Calculate start time: n days ago from now\n",
"days_ago = 30\n",
"start_time = int(time.time()) - (days_ago * 24 * 60 * 60)\n",
"\n",
"# Define the Costs API endpoint\n",
"costs_url = \"https://api.openai.com/v1/organization/costs\"\n",
"\n",
2025-02-11 09:28:49 -08:00
"costs_params = {\n",
" \"start_time\": start_time, # Required: Start time (Unix seconds)\n",
" \"bucket_width\": \"1d\", # Optional: Currently only '1d' is supported\n",
" \"limit\": 30, # Optional: Number of buckets to return\n",
"}\n",
2025-01-15 15:39:19 +00:00
"\n",
2025-02-11 09:28:49 -08:00
"# Initialize an empty list to store all data\n",
"all_costs_data = get_data(costs_url, costs_params)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1736553600,\n",
" \"end_time\": 1736640000,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.13080438340307526,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1736640000,\n",
" \"end_time\": 1736726400,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.12270423340307525,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1736726400,\n",
" \"end_time\": 1736812800,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 9.888144383403077,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1736812800,\n",
" \"end_time\": 1736899200,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.3507639334030752,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1736899200,\n",
" \"end_time\": 1736985600,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.2977481185324674,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1736985600,\n",
" \"end_time\": 1737072000,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.00925485477848094,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1737072000,\n",
" \"end_time\": 1737158400,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 8.889884136532304,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1737158400,\n",
" \"end_time\": 1737244800,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 21.167310118127915,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1737244800,\n",
" \"end_time\": 1737331200,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.04955636812791847,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1737331200,\n",
" \"end_time\": 1737417600,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.0003226181279184669,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1737417600,\n",
" \"end_time\": 1737504000,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.6320363681279185,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1737504000,\n",
" \"end_time\": 1737590400,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 52.41558761812793,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1737590400,\n",
" \"end_time\": 1737676800,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 104.88761235323427,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1737676800,\n",
" \"end_time\": 1737763200,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.3376030385950106,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1737763200,\n",
" \"end_time\": 1737849600,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.062551042553524,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1737849600,\n",
" \"end_time\": 1737936000,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.00032195744715549047,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1737936000,\n",
" \"end_time\": 1738022400,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.0003084210662774742,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1738022400,\n",
" \"end_time\": 1738108800,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.00032195744715549047,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1738108800,\n",
" \"end_time\": 1738195200,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.5142559074471554,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1738195200,\n",
" \"end_time\": 1738281600,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.21870350744715547,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1738281600,\n",
" \"end_time\": 1738368000,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 1.4528752074471551,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1738368000,\n",
" \"end_time\": 1738454400,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.00042714787262957543,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1738454400,\n",
" \"end_time\": 1738540800,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.00032195744715549047,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1738540800,\n",
" \"end_time\": 1738627200,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.0031147346857709622,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1738627200,\n",
" \"end_time\": 1738713600,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 68.30023964957941,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1738713600,\n",
" \"end_time\": 1738800000,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 14.858330207447157,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1738800000,\n",
" \"end_time\": 1738886400,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.3137180574471555,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1738886400,\n",
" \"end_time\": 1738972800,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.02677460744715549,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1738972800,\n",
" \"end_time\": 1739059200,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.007399792553524012,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1739059200,\n",
" \"end_time\": 1739145600,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.00032195744715549047,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"object\": \"bucket\",\n",
" \"start_time\": 1739145600,\n",
" \"end_time\": 1739232000,\n",
" \"results\": [\n",
" {\n",
" \"object\": \"organization.costs.result\",\n",
" \"amount\": {\n",
" \"value\": 0.00012073404268330895,\n",
" \"currency\": \"usd\"\n",
" },\n",
" \"line_item\": null,\n",
" \"project_id\": null,\n",
" \"organization_id\": \"org-GLHrIv00VVN9dEQC2b4wsBkf\"\n",
" }\n",
" ]\n",
" }\n",
"]\n"
]
}
],
"source": [
"print(json.dumps(all_costs_data, indent=2))"
2025-01-15 15:39:19 +00:00
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Parse the Costs API Response and Create a DataFrame\n",
"\n",
"We will now parse the JSON data from the Costs API, extract relevant fields, and create a pandas DataFrame for further analysis.\n"
]
},
{
"cell_type": "code",
2025-02-11 09:28:49 -08:00
"execution_count": 12,
2025-01-15 15:39:19 +00:00
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>start_time</th>\n",
" <th>end_time</th>\n",
" <th>amount_value</th>\n",
" <th>currency</th>\n",
" <th>line_item</th>\n",
" <th>project_id</th>\n",
" <th>start_datetime</th>\n",
" <th>end_datetime</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
2025-02-11 09:28:49 -08:00
" <td>1736553600</td>\n",
" <td>1736640000</td>\n",
" <td>0.130804</td>\n",
2025-01-15 15:39:19 +00:00
" <td>usd</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
2025-02-11 09:28:49 -08:00
" <td>2025-01-11</td>\n",
" <td>2025-01-12</td>\n",
2025-01-15 15:39:19 +00:00
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
2025-02-11 09:28:49 -08:00
" <td>1736640000</td>\n",
" <td>1736726400</td>\n",
" <td>0.122704</td>\n",
2025-01-15 15:39:19 +00:00
" <td>usd</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
2025-02-11 09:28:49 -08:00
" <td>2025-01-12</td>\n",
" <td>2025-01-13</td>\n",
2025-01-15 15:39:19 +00:00
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
2025-02-11 09:28:49 -08:00
" <td>1736726400</td>\n",
" <td>1736812800</td>\n",
" <td>9.888144</td>\n",
2025-01-15 15:39:19 +00:00
" <td>usd</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
2025-02-11 09:28:49 -08:00
" <td>2025-01-13</td>\n",
" <td>2025-01-14</td>\n",
2025-01-15 15:39:19 +00:00
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
2025-02-11 09:28:49 -08:00
" <td>1736812800</td>\n",
" <td>1736899200</td>\n",
" <td>0.350764</td>\n",
2025-01-15 15:39:19 +00:00
" <td>usd</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
2025-02-11 09:28:49 -08:00
" <td>2025-01-14</td>\n",
" <td>2025-01-15</td>\n",
2025-01-15 15:39:19 +00:00
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
2025-02-11 09:28:49 -08:00
" <td>1736899200</td>\n",
" <td>1736985600</td>\n",
" <td>0.297748</td>\n",
2025-01-15 15:39:19 +00:00
" <td>usd</td>\n",
" <td>None</td>\n",
" <td>None</td>\n",
2025-02-11 09:28:49 -08:00
" <td>2025-01-15</td>\n",
" <td>2025-01-16</td>\n",
2025-01-15 15:39:19 +00:00
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" start_time end_time amount_value currency line_item project_id \\\n",
2025-02-11 09:28:49 -08:00
"0 1736553600 1736640000 0.130804 usd None None \n",
"1 1736640000 1736726400 0.122704 usd None None \n",
"2 1736726400 1736812800 9.888144 usd None None \n",
"3 1736812800 1736899200 0.350764 usd None None \n",
"4 1736899200 1736985600 0.297748 usd None None \n",
2025-01-15 15:39:19 +00:00
"\n",
" start_datetime end_datetime \n",
2025-02-11 09:28:49 -08:00
"0 2025-01-11 2025-01-12 \n",
"1 2025-01-12 2025-01-13 \n",
"2 2025-01-13 2025-01-14 \n",
"3 2025-01-14 2025-01-15 \n",
"4 2025-01-15 2025-01-16 "
2025-01-15 15:39:19 +00:00
]
},
2025-02-11 09:28:49 -08:00
"execution_count": 12,
2025-01-15 15:39:19 +00:00
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Initialize a list to hold parsed cost records\n",
"cost_records = []\n",
"\n",
"# Extract bucketed cost data from all_costs_data\n",
"for bucket in all_costs_data:\n",
" start_time = bucket.get(\"start_time\")\n",
" end_time = bucket.get(\"end_time\")\n",
" for result in bucket.get(\"results\", []):\n",
2025-02-11 09:28:49 -08:00
" cost_records.append(\n",
" {\n",
" \"start_time\": start_time,\n",
" \"end_time\": end_time,\n",
" \"amount_value\": result.get(\"amount\", {}).get(\"value\", 0),\n",
" \"currency\": result.get(\"amount\", {}).get(\"currency\", \"usd\"),\n",
" \"line_item\": result.get(\"line_item\"),\n",
" \"project_id\": result.get(\"project_id\"),\n",
" }\n",
" )\n",
2025-01-15 15:39:19 +00:00
"\n",
"# Create a DataFrame from the cost records\n",
"cost_df = pd.DataFrame(cost_records)\n",
"\n",
"# Convert Unix timestamps to datetime for readability\n",
2025-02-11 09:28:49 -08:00
"cost_df[\"start_datetime\"] = pd.to_datetime(cost_df[\"start_time\"], unit=\"s\")\n",
"cost_df[\"end_datetime\"] = pd.to_datetime(cost_df[\"end_time\"], unit=\"s\")\n",
2025-01-15 15:39:19 +00:00
"\n",
"# Display the first few rows of the DataFrame\n",
"cost_df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
2025-02-11 09:28:49 -08:00
"## Visualize Total Costs per Day\n",
2025-01-15 15:39:19 +00:00
"\n",
2025-02-11 09:28:49 -08:00
"We'll create a bar chart to visualize the total costs aggregated by day. This helps give a high level perspective on organizational spend."
2025-01-15 15:39:19 +00:00
]
},
{
"cell_type": "code",
2025-02-11 09:28:49 -08:00
"execution_count": 13,
2025-01-15 15:39:19 +00:00
"metadata": {},
"outputs": [
{
"data": {
2025-02-11 09:28:49 -08:00
"image/png": "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TM8//7xCQkJ08OBBffXVV5KksLAwTZ8+XU888YQefPBBPfTQQ5KUp9Pe+vfvr5CQEL388svat2+fpk+frkOHDtknds/++XXr1k1xcXGaMGGCUlJSNH36dN15553asmWLPfSQLoVscXFxuvPOO/X666/n++fn6NFHH9ULL7ygH3/8Ub1795YkLV68WH/88Yd69OihiIgI+6mQu3bt0tq1a+3BTVRUlObMmaMHH3wwxzbnzJmjihUrKjY29qrPu2nTJqWlpalu3boFqvuLL75QSkqKnnjiCYWGhmr9+vV6++239eeff+qLL76wr9e+fXvt2rVLTz31lCpUqKATJ05o8eLFOnz4sCpUqKDJkyfb57R68cUXJUnh4eH/+PwZGRlKSEhQWlqadu7cqZdeekmBgYG6/fbb7ets2bJFVapUuez0uux1tm7dqqioqAK9funSvvvxxx+1ePFiValSRdKlILR48eIaPHiwihcvrqVLl2rEiBFKSkrSa6+9Zn/c6NGj9dlnn6l///727aWlpWnevHlq3769/Pz8/vE94ahevXp68803tWvXLtWoUaPArwkAAMsYAADgcvr162cc/5meP3++kWTGjh2bY70OHToYm81mfv/9d/tYQECA6dat22XbTElJuWxszZo1RpL56KOP7GPLli0zksyyZcuuWl9iYqKRZNq2bZun17N161YjyfTq1SvH+DPPPGMkmaVLlxpjjPn666+NJLNhw4arbuvkyZNGkhk5cmSennvGjBlGkqlXr55JS0uzj0+cONFIMt98840xxphz586ZkJAQ07t37xyPP378uAkODs4x3q1bNyPJPP/88/mq4e9eV3BwsImJibHfv9L++uSTT4wks3LlSvvYsGHDjK+vr0lISLCPnThxwnh5ef3jz+iDDz4wksyOHTsuW1a+fHnTsmXLv338lWocP368sdls5tChQ8YYY86ePWskmddee+1vt3Xrrbeaxo0b/+06uWX3b/btlltuuaxvb731VtO0adPLHrtr1y4jybz77rt/+xzdunUzAQEBV12+ZcsWI8kMGjTIPnaln0vfvn1NsWLFzMWLF+1jsbGxpkGDBjnW++qrr3K8//Lynsi2evVqI8l89tln/7guAACugNP3AAC4Dvzvf/+Tp6ennn766RzjQ4YMkTFG33///T9uw3GuovT0dJ0+fVqVKlVSSEiINm/enK96kpKSJEmBgYF5Wj/7UvWDBw/OMT5kyBBJss89FRISIkn69ttvlZ6enq+a/kmfPn3k7e1tv//EE0/Iy8vLXtvixYuVkJCgRx55RKdOnbLfPD091aBBAy1btuyybT7xxBOFVl/x4sVzXIXPcX9dvHhRp06dss+T5Li/unbtqtTUVM2bN88+9tlnnykjI+Mf5yTLPhWwRIkSBarZscbz58/r1KlTatiwoYwx2rJli30dHx8fLV++/IqnS16L6tWra/HixZo/f76GDh2qgICAy66+d+HCBfn6+l72WD8/P/vya5F9xcKr7btz587p1KlTuuuuu5SSkqK9e/fal3Xt2lXr1q3T/v377WNz5sxRVFSUGjduLCl/74ns/Xjq1Klrek0AAFiFUAoAgOvAoUOHFBkZeVkIlH01vkOHDv3jNi5cuKARI0bY56QqVaqUwsLClJCQoMTExHzVk30qlOMf4v9
2025-01-15 15:39:19 +00:00
"text/plain": [
"<Figure size 1200x600 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"if not cost_df.empty:\n",
" # Ensure datetime conversion for 'start_datetime' column\n",
2025-02-11 09:28:49 -08:00
" if (\n",
" \"start_datetime\" not in cost_df.columns\n",
" or not pd.api.types.is_datetime64_any_dtype(cost_df[\"start_datetime\"])\n",
" ):\n",
" cost_df[\"start_datetime\"] = pd.to_datetime(\n",
" cost_df[\"start_time\"], unit=\"s\", errors=\"coerce\"\n",
" )\n",
2025-01-15 15:39:19 +00:00
"\n",
" # Create a new column for just the date part of 'start_datetime'\n",
2025-02-11 09:28:49 -08:00
" cost_df[\"date\"] = cost_df[\"start_datetime\"].dt.date\n",
"\n",
2025-01-15 15:39:19 +00:00
" # Group by date and sum the amounts\n",
2025-02-11 09:28:49 -08:00
" cost_per_day = cost_df.groupby(\"date\")[\"amount_value\"].sum().reset_index()\n",
"\n",
2025-01-15 15:39:19 +00:00
" # Plot the data\n",
" plt.figure(figsize=(12, 6))\n",
2025-02-11 09:28:49 -08:00
" plt.bar(\n",
" cost_per_day[\"date\"],\n",
" cost_per_day[\"amount_value\"],\n",
" width=0.6,\n",
" color=\"skyblue\",\n",
" alpha=0.8,\n",
" )\n",
" plt.xlabel(\"Date\")\n",
" plt.ylabel(\"Total Cost (USD)\")\n",
" plt.title(\"Total Cost per Day (Last 30 Days)\")\n",
" plt.xticks(rotation=45, ha=\"right\")\n",
" plt.tight_layout()\n",
" plt.show()\n",
"else:\n",
" print(\"No cost data available to plot.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Visualize Costs by Line Item\n",
"\n",
"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."
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Data retrieved successfully!\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>start_time</th>\n",
" <th>end_time</th>\n",
" <th>amount_value</th>\n",
" <th>currency</th>\n",
" <th>line_item</th>\n",
" <th>project_id</th>\n",
" <th>start_datetime</th>\n",
" <th>end_datetime</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>1736553600</td>\n",
" <td>1736640000</td>\n",
" <td>0.127440</td>\n",
" <td>usd</td>\n",
" <td>ft-gpt-4o-2024-08-06, input</td>\n",
" <td>proj_hNhhQzyYu7HxySZWs7cA3Ugu</td>\n",
" <td>2025-01-11</td>\n",
" <td>2025-01-12</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1736553600</td>\n",
" <td>1736640000</td>\n",
" <td>0.003090</td>\n",
" <td>usd</td>\n",
" <td>ft-gpt-4o-2024-08-06, output</td>\n",
" <td>proj_hNhhQzyYu7HxySZWs7cA3Ugu</td>\n",
" <td>2025-01-11</td>\n",
" <td>2025-01-12</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>1736553600</td>\n",
" <td>1736640000</td>\n",
" <td>0.000271</td>\n",
" <td>usd</td>\n",
" <td>assistants api | file search</td>\n",
" <td>proj_L67gOme4S2nBA8aQieEOwLy7</td>\n",
" <td>2025-01-11</td>\n",
" <td>2025-01-12</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>1736553600</td>\n",
" <td>1736640000</td>\n",
" <td>0.000003</td>\n",
" <td>usd</td>\n",
" <td>assistants api | file search</td>\n",
" <td>proj_VV4ZAjd6ALfFd9uh0vY8joR1</td>\n",
" <td>2025-01-11</td>\n",
" <td>2025-01-12</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>1736640000</td>\n",
" <td>1736726400</td>\n",
" <td>0.028607</td>\n",
" <td>usd</td>\n",
" <td>evals | gpt-4o-mini-2024-07-18, input</td>\n",
" <td>proj_L67gOme4S2nBA8aQieEOwLy7</td>\n",
" <td>2025-01-12</td>\n",
" <td>2025-01-13</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" start_time end_time amount_value currency \\\n",
"0 1736553600 1736640000 0.127440 usd \n",
"1 1736553600 1736640000 0.003090 usd \n",
"2 1736553600 1736640000 0.000271 usd \n",
"3 1736553600 1736640000 0.000003 usd \n",
"4 1736640000 1736726400 0.028607 usd \n",
"\n",
" line_item project_id \\\n",
"0 ft-gpt-4o-2024-08-06, input proj_hNhhQzyYu7HxySZWs7cA3Ugu \n",
"1 ft-gpt-4o-2024-08-06, output proj_hNhhQzyYu7HxySZWs7cA3Ugu \n",
"2 assistants api | file search proj_L67gOme4S2nBA8aQieEOwLy7 \n",
"3 assistants api | file search proj_VV4ZAjd6ALfFd9uh0vY8joR1 \n",
"4 evals | gpt-4o-mini-2024-07-18, input proj_L67gOme4S2nBA8aQieEOwLy7 \n",
"\n",
" start_datetime end_datetime \n",
"0 2025-01-11 2025-01-12 \n",
"1 2025-01-11 2025-01-12 \n",
"2 2025-01-11 2025-01-12 \n",
"3 2025-01-11 2025-01-12 \n",
"4 2025-01-12 2025-01-13 "
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"days_ago = 30\n",
"start_time = int(time.time()) - (days_ago * 24 * 60 * 60)\n",
"\n",
"costs_params = {\n",
" \"start_time\": start_time, # Required: Start time (Unix seconds)\n",
" \"bucket_width\": \"1d\", # Optional: Currently only '1d' is supported\n",
" \"limit\": 30, # Optional: Number of buckets to return\n",
" \"group_by\": [\"line_item\"],\n",
"}\n",
"\n",
"line_item_cost_data = get_data(costs_url, costs_params)\n",
"\n",
"# Initialize a list to hold parsed cost records\n",
"cost_records = []\n",
"\n",
"# Extract bucketed cost data from all_costs_data\n",
"for bucket in line_item_cost_data:\n",
" start_time = bucket.get(\"start_time\")\n",
" end_time = bucket.get(\"end_time\")\n",
" for result in bucket.get(\"results\", []):\n",
" cost_records.append(\n",
" {\n",
" \"start_time\": start_time,\n",
" \"end_time\": end_time,\n",
" \"amount_value\": result.get(\"amount\", {}).get(\"value\", 0),\n",
" \"currency\": result.get(\"amount\", {}).get(\"currency\", \"usd\"),\n",
" \"line_item\": result.get(\"line_item\"),\n",
" \"project_id\": result.get(\"project_id\"),\n",
" }\n",
" )\n",
"\n",
"# Create a DataFrame from the cost records\n",
"cost_df = pd.DataFrame(cost_records)\n",
"\n",
"# Convert Unix timestamps to datetime for readability\n",
"cost_df[\"start_datetime\"] = pd.to_datetime(cost_df[\"start_time\"], unit=\"s\")\n",
"cost_df[\"end_datetime\"] = pd.to_datetime(cost_df[\"end_time\"], unit=\"s\")\n",
"\n",
"# Display the first few rows of the DataFrame\n",
"cost_df.head()"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/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.\n",
" plt.tight_layout()\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABlwAAAUSCAYAAABsMFygAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdeViN6f8H8Pc5pTrtSiRFSVGiZmxDGUVkyzLWpIUwhpDIGIzKlrXJNtmlmdLYMtaMLM1oLDlfGUsTIRkSokKWdM7vj66en6NFCVner+s619V5nvv+3J/nOc93vnU+7vsWyeVyOYiIiIiIiIiIiIiIiOiNias7ASIiIiIiIiIiIiIioo8dCy5ERERERERERERERERVxIILERERERERERERERFRFbHgQkREREREREREREREVEUsuBAREREREREREREREVURCy5ERERERERERERERERVxIILERERERERERERERFRFbHgQkREREREREREREREVEUsuBAREREREREREREREVURCy5ERERv2dGjRyESiXD06NHqTuWtiIiIgEgkwunTp6s7FSGX9PT06k6FiIiIiIiIiEgBCy5ERPRJEIlEFXpVpAgyb9487Ny5853nXOzKlSv49ttv0bBhQ6ipqUFbWxv29vZYunQpnjx58tbHy8/PR1BQ0AdXEPL29oampmZ1p1EmR0dH2NjYKBx7388KEREREREREX24lKs7ASIiorfhl19+UXgfGRmJgwcPljhuZWX12ljz5s1D//790adPn7eZYqn27t2LAQMGQFVVFZ6enrCxscHz589x7NgxBAQE4MKFC1izZs1bHTM/Px/BwcEAiooIHxMPDw8MHjwYqqqq1Z0KgPf7rBARERERERHRh40FFyIi+iQMHTpU4f2JEydw8ODBEsc/JNeuXcPgwYPRoEEDHD58GHXr1hXOjR07Fmlpadi7d281ZvjhUVJSgpKSUnWnQURERERERERUApcUIyKiz8bjx48xadIkmJiYQFVVFY0bN8bixYshl8uFNiKRCI8fP8amTZuEZci8vb0BANevX8eYMWPQuHFjSCQS6OvrY8CAAW+8n8jChQvx6NEjrF+/XqHYUqxRo0aYMGGC8P7FixeYPXs2zM3NoaqqClNTU0ybNg3Pnj1T6Hf69Gm4uLigVq1akEgkMDMzw/DhwwEA6enpMDAwAAAE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
"text/plain": [
"<Figure size 1200x600 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"if not cost_df.empty:\n",
" # Ensure datetime conversion for 'start_datetime' column\n",
" if \"start_datetime\" not in cost_df.columns or not pd.api.types.is_datetime64_any_dtype(cost_df[\"start_datetime\"]):\n",
" cost_df[\"start_datetime\"] = pd.to_datetime(cost_df[\"start_time\"], unit=\"s\", errors=\"coerce\")\n",
"\n",
" # Create a new column for just the date part of 'start_datetime'\n",
" cost_df[\"date\"] = cost_df[\"start_datetime\"].dt.date\n",
"\n",
" # Group by date and line_item and sum the amounts\n",
" cost_per_day = cost_df.groupby([\"date\", \"line_item\"])[\"amount_value\"].sum().reset_index()\n",
"\n",
" # Pivot the DataFrame so each date has one bar with line_item stacks\n",
" cost_pivot = cost_per_day.pivot(index=\"date\", columns=\"line_item\", values=\"amount_value\").fillna(0)\n",
" cost_pivot = cost_pivot.sort_index()\n",
"\n",
" # Plot a stacked bar chart with one bar for each grouped day\n",
" plt.figure(figsize=(12, 6))\n",
" ax = cost_pivot.plot(kind=\"bar\", stacked=True, ax=plt.gca(), width=0.8)\n",
" plt.xlabel(\"Date\")\n",
" plt.ylabel(\"Total Cost (USD)\")\n",
" plt.title(\"Total Cost by Line Item\")\n",
" plt.xticks(rotation=45, ha=\"right\")\n",
" # Update legend so it doesn't overlay the graph by placing it outside the plot area\n",
" plt.legend(bbox_to_anchor=(1.05, 1), loc=\"upper left\", borderaxespad=0.)\n",
2025-01-15 15:39:19 +00:00
" plt.tight_layout()\n",
" plt.show()\n",
"else:\n",
" print(\"No cost data available to plot.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Additional Visualizations (Optional)\n",
"\n",
"You can extend this notebook with more visualizations for both the Completions and Costs APIs. For example:\n",
"\n",
"**Completions API:**\n",
"- Group by user, project, or model to see which ones consume the most tokens.\n",
"- Create line plots for time series analysis of token usage over days or hours.\n",
"- Use pie charts to visualize distribution of tokens across models, users, or projects.\n",
"- Experiment with different `group_by` parameters (e.g., `[\"model\", \"user_id\"]`) to gain deeper insights.\n",
"\n",
"**Costs API:**\n",
"- Group by project or line item to identify spending patterns.\n",
"- Create line or bar charts to visualize daily cost trends.\n",
"- Use pie charts to show how costs are distributed across projects, services, or line items.\n",
"- Try various `group_by` options (e.g., `[\"project_id\"]`, `[\"line_item\"]`) for granular analysis.\n",
"\n",
"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.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Integrating with Third-Party Dashboarding Platforms\n",
"\n",
"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:\n",
"\n",
"1. **Data Collection & Preparation:**\n",
" - Use Python scripts to regularly fetch data from the Completions and Costs APIs.\n",
" - Process and aggregate the data with pandas, then store it in a database, data warehouse, or export it as CSV/JSON files.\n",
"\n",
"2. **Connecting to a Dashboard:**\n",
" - **BI Tools (Tableau, Power BI):**\n",
" - Connect directly to the prepared data source (SQL database, CSV files, or web APIs).\n",
" - Use built-in connectors to schedule data refreshes, ensuring dashboards always display current information.\n",
" - **Custom Dashboards (Plotly Dash, Bokeh):**\n",
" - Embed API calls and data processing into the dashboard code.\n",
" - Build interactive visual components that automatically update as new data is fetched.\n",
"\n",
"3. **Real-Time & Automated Updates:**\n",
" - Schedule scripts using cron jobs, task schedulers, or workflow tools (e.g., Apache Airflow) to refresh data periodically.\n",
" - Implement webhooks or streaming APIs (if available) for near real-time data updates.\n",
"\n",
"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.\n"
]
}
],
"metadata": {
"kernelspec": {
2025-02-11 09:28:49 -08:00
"display_name": "openai",
2025-01-15 15:39:19 +00:00
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
2025-02-11 09:28:49 -08:00
"version": "3.11.8"
2025-01-15 15:39:19 +00:00
}
},
"nbformat": 4,
"nbformat_minor": 2
}