mirror of
https://github.com/james-m-jordan/openai-cookbook.git
synced 2025-05-09 19:32:38 +00:00
1839 lines
439 KiB
Plaintext
1839 lines
439 KiB
Plaintext
![]() |
{
|
||
|
"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",
|
||
|
"execution_count": 13,
|
||
|
"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",
|
||
|
"%matplotlib inline\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"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",
|
||
|
"Replace `'PLACEHOLDER'` with your actual ADMIN API key. It's best practice to load the key from an environment variable for security.\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 3,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"name": "stdout",
|
||
|
"output_type": "stream",
|
||
|
"text": [
|
||
|
"Data retrieved successfully!\n"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"# 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",
|
||
|
"# 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",
|
||
|
" \"bucket_width\": \"1d\", # Optional: '1m', '1h', or '1d' (default '1d')\n",
|
||
|
" # \"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",
|
||
|
" # \"models\": [\"gpt-4o-mini-2024-07-18\"], # Optional: List of models\n",
|
||
|
" # \"batch\": False, # Optional: True for batch jobs, False for non-batch\n",
|
||
|
" # \"group_by\": [\"model\"], # Optional: Fields to group by\n",
|
||
|
" \"limit\": 7, # Optional: Number of buckets to return, this will chunk the data into 7 buckets\n",
|
||
|
" # \"page\": \"cursor_string\" # Optional: Cursor for pagination\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.\")"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"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",
|
||
|
" \"start_time\": 1734345977,\n",
|
||
|
" \"end_time\": 1734393600,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 300245,\n",
|
||
|
" \"output_tokens\": 534874,\n",
|
||
|
" \"num_model_requests\": 298,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 53120,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1734393600,\n",
|
||
|
" \"end_time\": 1734480000,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 8,\n",
|
||
|
" \"output_tokens\": 9,\n",
|
||
|
" \"num_model_requests\": 1,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 0,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1734480000,\n",
|
||
|
" \"end_time\": 1734566400,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 19287,\n",
|
||
|
" \"output_tokens\": 1770,\n",
|
||
|
" \"num_model_requests\": 24,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 15104,\n",
|
||
|
" \"input_audio_tokens\": 47248,\n",
|
||
|
" \"output_audio_tokens\": 6403\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1734566400,\n",
|
||
|
" \"end_time\": 1734652800,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 19162,\n",
|
||
|
" \"output_tokens\": 5115,\n",
|
||
|
" \"num_model_requests\": 38,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 3584,\n",
|
||
|
" \"input_audio_tokens\": 21218,\n",
|
||
|
" \"output_audio_tokens\": 12483\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1734652800,\n",
|
||
|
" \"end_time\": 1734739200,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 50882,\n",
|
||
|
" \"output_tokens\": 24867,\n",
|
||
|
" \"num_model_requests\": 28,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 0,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1734739200,\n",
|
||
|
" \"end_time\": 1734825600,\n",
|
||
|
" \"results\": []\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1734825600,\n",
|
||
|
" \"end_time\": 1734912000,\n",
|
||
|
" \"results\": []\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1734912000,\n",
|
||
|
" \"end_time\": 1734998400,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 14642697,\n",
|
||
|
" \"output_tokens\": 164700,\n",
|
||
|
" \"num_model_requests\": 11300,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 151296,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1734998400,\n",
|
||
|
" \"end_time\": 1735084800,\n",
|
||
|
" \"results\": []\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1735084800,\n",
|
||
|
" \"end_time\": 1735171200,\n",
|
||
|
" \"results\": []\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1735171200,\n",
|
||
|
" \"end_time\": 1735257600,\n",
|
||
|
" \"results\": []\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1735257600,\n",
|
||
|
" \"end_time\": 1735344000,\n",
|
||
|
" \"results\": []\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1735344000,\n",
|
||
|
" \"end_time\": 1735430400,\n",
|
||
|
" \"results\": []\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1735430400,\n",
|
||
|
" \"end_time\": 1735516800,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 84150,\n",
|
||
|
" \"output_tokens\": 502,\n",
|
||
|
" \"num_model_requests\": 232,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 0,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1735516800,\n",
|
||
|
" \"end_time\": 1735603200,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 118904,\n",
|
||
|
" \"output_tokens\": 57094,\n",
|
||
|
" \"num_model_requests\": 331,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 0,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1735603200,\n",
|
||
|
" \"end_time\": 1735689600,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 175320,\n",
|
||
|
" \"output_tokens\": 67638,\n",
|
||
|
" \"num_model_requests\": 515,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 0,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1735689600,\n",
|
||
|
" \"end_time\": 1735776000,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 1515,\n",
|
||
|
" \"output_tokens\": 11,\n",
|
||
|
" \"num_model_requests\": 5,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 0,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1735776000,\n",
|
||
|
" \"end_time\": 1735862400,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 527323,\n",
|
||
|
" \"output_tokens\": 40396,\n",
|
||
|
" \"num_model_requests\": 283,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 1152,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1735862400,\n",
|
||
|
" \"end_time\": 1735948800,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 31027,\n",
|
||
|
" \"output_tokens\": 242,\n",
|
||
|
" \"num_model_requests\": 106,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 0,\n",
|
||
|
" \"input_audio_tokens\": 12,\n",
|
||
|
" \"output_audio_tokens\": 29\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1735948800,\n",
|
||
|
" \"end_time\": 1736035200,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 77053,\n",
|
||
|
" \"output_tokens\": 51801,\n",
|
||
|
" \"num_model_requests\": 255,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 0,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1736035200,\n",
|
||
|
" \"end_time\": 1736121600,\n",
|
||
|
" \"results\": []\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1736121600,\n",
|
||
|
" \"end_time\": 1736208000,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 598758,\n",
|
||
|
" \"output_tokens\": 575020,\n",
|
||
|
" \"num_model_requests\": 1941,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 12480,\n",
|
||
|
" \"input_audio_tokens\": 23843,\n",
|
||
|
" \"output_audio_tokens\": 2441\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1736208000,\n",
|
||
|
" \"end_time\": 1736294400,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 81383,\n",
|
||
|
" \"output_tokens\": 38568,\n",
|
||
|
" \"num_model_requests\": 284,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 0,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1736294400,\n",
|
||
|
" \"end_time\": 1736380800,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 81272,\n",
|
||
|
" \"output_tokens\": 208562,\n",
|
||
|
" \"num_model_requests\": 265,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 0,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1736380800,\n",
|
||
|
" \"end_time\": 1736467200,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 873554,\n",
|
||
|
" \"output_tokens\": 31703,\n",
|
||
|
" \"num_model_requests\": 413,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 691584,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1736467200,\n",
|
||
|
" \"end_time\": 1736553600,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 129753,\n",
|
||
|
" \"output_tokens\": 65335,\n",
|
||
|
" \"num_model_requests\": 184,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 0,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1736553600,\n",
|
||
|
" \"end_time\": 1736640000,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 141874,\n",
|
||
|
" \"output_tokens\": 9831,\n",
|
||
|
" \"num_model_requests\": 473,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 0,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1736640000,\n",
|
||
|
" \"end_time\": 1736726400,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 45949,\n",
|
||
|
" \"output_tokens\": 282,\n",
|
||
|
" \"num_model_requests\": 150,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 0,\n",
|
||
|
" \"input_audio_tokens\": 0,\n",
|
||
|
" \"output_audio_tokens\": 0\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1736726400,\n",
|
||
|
" \"end_time\": 1736812800,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 3718360,\n",
|
||
|
" \"output_tokens\": 97756,\n",
|
||
|
" \"num_model_requests\": 3053,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 76544,\n",
|
||
|
" \"input_audio_tokens\": 5776,\n",
|
||
|
" \"output_audio_tokens\": 3166\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1736812800,\n",
|
||
|
" \"end_time\": 1736899200,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 52786,\n",
|
||
|
" \"output_tokens\": 38204,\n",
|
||
|
" \"num_model_requests\": 157,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 5440,\n",
|
||
|
" \"input_audio_tokens\": 4066,\n",
|
||
|
" \"output_audio_tokens\": 1097\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" },\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"bucket\",\n",
|
||
|
" \"start_time\": 1736899200,\n",
|
||
|
" \"end_time\": 1736937980,\n",
|
||
|
" \"results\": [\n",
|
||
|
" {\n",
|
||
|
" \"object\": \"organization.usage.completions.result\",\n",
|
||
|
" \"input_tokens\": 9588,\n",
|
||
|
" \"output_tokens\": 224,\n",
|
||
|
" \"num_model_requests\": 34,\n",
|
||
|
" \"project_id\": null,\n",
|
||
|
" \"user_id\": null,\n",
|
||
|
" \"api_key_id\": null,\n",
|
||
|
" \"model\": null,\n",
|
||
|
" \"batch\": null,\n",
|
||
|
" \"service_tier\": null,\n",
|
||
|
" \"input_cached_tokens\": 192,\n",
|
||
|
" \"input_audio_tokens\": 349,\n",
|
||
|
" \"output_audio_tokens\": 499\n",
|
||
|
" }\n",
|
||
|
" ]\n",
|
||
|
" }\n",
|
||
|
"]\n"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"print(json.dumps(all_data, indent=2))"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"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",
|
||
|
" <th>service_tier</th>\n",
|
||
|
" </tr>\n",
|
||
|
" </thead>\n",
|
||
|
" <tbody>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>0</th>\n",
|
||
|
" <td>2024-12-16 10:46:17</td>\n",
|
||
|
" <td>2024-12-17</td>\n",
|
||
|
" <td>1734345977</td>\n",
|
||
|
" <td>1734393600</td>\n",
|
||
|
" <td>300245</td>\n",
|
||
|
" <td>534874</td>\n",
|
||
|
" <td>53120</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>298</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <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",
|
||
|
" <td>2024-12-17 00:00:00</td>\n",
|
||
|
" <td>2024-12-18</td>\n",
|
||
|
" <td>1734393600</td>\n",
|
||
|
" <td>1734480000</td>\n",
|
||
|
" <td>8</td>\n",
|
||
|
" <td>9</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>1</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <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",
|
||
|
" <td>2024-12-18 00:00:00</td>\n",
|
||
|
" <td>2024-12-19</td>\n",
|
||
|
" <td>1734480000</td>\n",
|
||
|
" <td>1734566400</td>\n",
|
||
|
" <td>19287</td>\n",
|
||
|
" <td>1770</td>\n",
|
||
|
" <td>15104</td>\n",
|
||
|
" <td>47248</td>\n",
|
||
|
" <td>6403</td>\n",
|
||
|
" <td>24</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <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",
|
||
|
" <td>2024-12-19 00:00:00</td>\n",
|
||
|
" <td>2024-12-20</td>\n",
|
||
|
" <td>1734566400</td>\n",
|
||
|
" <td>1734652800</td>\n",
|
||
|
" <td>19162</td>\n",
|
||
|
" <td>5115</td>\n",
|
||
|
" <td>3584</td>\n",
|
||
|
" <td>21218</td>\n",
|
||
|
" <td>12483</td>\n",
|
||
|
" <td>38</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <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",
|
||
|
" <td>2024-12-20 00:00:00</td>\n",
|
||
|
" <td>2024-12-21</td>\n",
|
||
|
" <td>1734652800</td>\n",
|
||
|
" <td>1734739200</td>\n",
|
||
|
" <td>50882</td>\n",
|
||
|
" <td>24867</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>28</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <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",
|
||
|
"0 2024-12-16 10:46:17 2024-12-17 1734345977 1734393600 300245 \n",
|
||
|
"1 2024-12-17 00:00:00 2024-12-18 1734393600 1734480000 8 \n",
|
||
|
"2 2024-12-18 00:00:00 2024-12-19 1734480000 1734566400 19287 \n",
|
||
|
"3 2024-12-19 00:00:00 2024-12-20 1734566400 1734652800 19162 \n",
|
||
|
"4 2024-12-20 00:00:00 2024-12-21 1734652800 1734739200 50882 \n",
|
||
|
"\n",
|
||
|
" output_tokens input_cached_tokens input_audio_tokens \\\n",
|
||
|
"0 534874 53120 0 \n",
|
||
|
"1 9 0 0 \n",
|
||
|
"2 1770 15104 47248 \n",
|
||
|
"3 5115 3584 21218 \n",
|
||
|
"4 24867 0 0 \n",
|
||
|
"\n",
|
||
|
" output_audio_tokens num_model_requests project_id user_id api_key_id \\\n",
|
||
|
"0 0 298 None None None \n",
|
||
|
"1 0 1 None None None \n",
|
||
|
"2 6403 24 None None None \n",
|
||
|
"3 12483 38 None None None \n",
|
||
|
"4 0 28 None None None \n",
|
||
|
"\n",
|
||
|
" model batch service_tier \n",
|
||
|
"0 None None None \n",
|
||
|
"1 None None None \n",
|
||
|
"2 None None None \n",
|
||
|
"3 None None None \n",
|
||
|
"4 None None None "
|
||
|
]
|
||
|
},
|
||
|
"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",
|
||
|
"for bucket in all_data: \n",
|
||
|
" start_time = bucket.get(\"start_time\")\n",
|
||
|
" end_time = bucket.get(\"end_time\")\n",
|
||
|
" for result in bucket.get(\"results\", []):\n",
|
||
|
" records.append({\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",
|
||
|
" \"service_tier\": result.get(\"service_tier\")\n",
|
||
|
" })\n",
|
||
|
"\n",
|
||
|
"# Create a DataFrame from the records\n",
|
||
|
"df = pd.DataFrame(records)\n",
|
||
|
"\n",
|
||
|
"# Convert Unix timestamps to datetime for readability\n",
|
||
|
"df['start_datetime'] = pd.to_datetime(df['start_time'], unit='s')\n",
|
||
|
"df['end_datetime'] = pd.to_datetime(df['end_time'], unit='s')\n",
|
||
|
"\n",
|
||
|
"# Reorder columns for better readability\n",
|
||
|
"df = df[\n",
|
||
|
" [\n",
|
||
|
" \"start_datetime\", \"end_datetime\", \"start_time\", \"end_time\",\n",
|
||
|
" \"input_tokens\", \"output_tokens\", \"input_cached_tokens\",\n",
|
||
|
" \"input_audio_tokens\", \"output_audio_tokens\", \"num_model_requests\",\n",
|
||
|
" \"project_id\", \"user_id\", \"api_key_id\", \"model\", \"batch\", \"service_tier\"\n",
|
||
|
" ]\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": {
|
||
|
"image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAJOCAYAAABm7rQwAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAffNJREFUeJzt3QncTPX////XZd9C9kjWFBGyRZ92UmnRquUTCe0JJVT2ChVp0aJIm9K+R/JJi5QlWpAWimSN7FnP//Z8//5nvnNdBtfFNWfmzDzut9twzZkzM885c+bMOa95v98nw/M8zwAAAAAAAIAA5QnyyQAAAAAAAAChKAUAAAAAAIDAUZQCAAAAAABA4ChKAQAAAAAAIHAUpQAAAAAAABA4ilIAAAAAAAAIHEUpAAAAAAAABI6iFAAAAAAAAAJHUQoAAAAAAACBoygFAEgb48aNs4yMDPv9998j00455RR3AcKgatWqds455yQ6BgAAQK6gKAUASMrCkX8pVKiQVaxY0Vq3bm2PPPKIbdy40ZKZMt98882WLMaPH28jR460ZLJ582YbPHiwHXvssVakSBErUaKEnXjiifb888+b53kH/LgffvihDRgwwIKwZcsW91xTp07NViEpep3e20XrfpiomFu3bt2Yt61Zs8a9pqDej3hRfr0OvZ4gfPXVV+45//nnn2zN/9Zbb7lto7aRBQsWtMMPP9wuvvhi+/HHH2PO/+6779pxxx3ntqtHHHGE9e/f33bu3Lnf59F6Hr2u6rnKly/v1oH77rvPVq9enePXCgCA5GMxAACS0aBBg6xatWq2Y8cOW7FihTso6tatm40YMcIdWKmgkVNXXXWVXXbZZe6AKl2oKKUDVC27ZLBy5Uo7/fTTbcGCBe69UAHv33//tTfeeMM6dOjgCksvvfSS5c2bN8ePrfuOGjUqkEKIilIDBw50f++vpZ2Kgps2bcqU8+WXX7aHHnrIypQpE5neokWLOCZGGKgopfXq6quvtpIlS+53/h9++MEOPfRQu/XWW926pG3l2LFjrWnTpjZ9+nSrX79+ZN6PPvrI2rZt69bXRx991N33nnvusVWrVtkTTzyRrXxdu3a1Jk2a2K5du1whSnlV2NJ2+dVXX7XTTjvtoF4/ACD9UJQCACSls846yxo3bhy53qdPH/vf//7nui6dd955rqhRuHDhHD2mCh0HUuxA7lHhSe+dWnjofYw+2O3Zs6c9+OCD1rBhQ+vVq5elChUCoqlwoKKUpqsVFXCg+vXrt8e0zp07uxZTKjQ9+eSTkem33367K+Z//PHHli/f/zsEKF68uGvppKLW0Ucfvd/nU4tGtcSK9t1339kZZ5xhF110kc2fP98OO+ywXHltAID0QPc9AEBo6Ff4vn372h9//GEvvvhiZPr333/vWhZUr17ddUupUKGCXXPNNfb333/vd0ypaGrNUrRoUXeAltWff/7pClpDhgzJUWa/24taEdx7773uYFEZ1Vro119/jdkdavbs2a7VjIpuai0WfWC5r9fhP5ffpUyP98EHH7jl5Xe72VcRRM996qmn7jF99+7dVqlSpUwHo6+88oo1atTIDjnkEHdgW69ePXv44Yf3uSy+/vprmzRpknuvogtSPi3bI4880oYNG2Zbt26N+Zp8eu3RXd70mGolJdHdjKLnVcFLrZOqVKnilu3JJ5+8RzenvY0xpsf3l50er2zZsu5vtWrxn+tgWmipC5W6NNaoUcO15NNz3XnnnbZt27b93ve5555zRQYV9XzffPONnXnmma5rpLpI6rVOmzYtZtc0rYd+yxzN37FjR9cSLLep661a7Om16TWWK1fOWrVqZd9++21kni+++MIuueQS17VM81SuXNm6d+8eWR+ivfbaa1anTh33edK6q0Jn9PsUvf6qtdoxxxzj5lW3s+uuu87WrVuXK69r7dq1ruCjz0CxYsXc50FFdRVrslILJeXQe6IWTiq8qzWj/37476E+9/56tbft1d5ouerxo7sAqliky7XXXhspSMmNN97ousy+/vrrB/z61RpLy1fP99hjj0Wma7ujxz/qqKPc56106dLuvY1+PYsWLXKvUZ/LrNQKS7epgJvd9QcAED60lAIAhIq64OlgXb/2d+nSxU2bPHmyO7jRwbQKUvPmzbPRo0e7/1UI8YsT+6MDygsuuMAmTJjguqNEt6rSgZEO3q688soDyj106FDLkyePO3hdv3693X///e6xVDyIpgPls88+2y699FK7/PLLXTHrhhtusAIFCrhCW07cdddd7rlUUPMP+vQa96Zdu3buwFgtebQcfV9++aX99ddfrrudv7yVTYU1FZBErZ9U9IhV0PO999577v/27dvHvF0Hy1dccYUr9OixWrZsme3XqiKDMirbCy+8EHMejVmlA9ubbrrJdRlUEU2FTnVjUqEiu1SQUisUvS9aXy688EI3/UC6lEa3blFxSYW/2267za0XKtL5rcr2Ruv59ddf7z4T6oolalGoooiKhupapfXu2Wefda9VRR917YqmdU1FED2fDvCfeeYZd8Dvv7e5RTlV/FCXTRWTVDTWuqXXqHGO/EKTCmJatipizJgxwxVytA7rNp+KrVpfVQhSbn1uOnXq5IqnsdYNFS+1fVCLvMWLF7viyZw5c9x6lj9//oN6Xdr2vP32267gouWoLqpPPfWUKwSqEKTxnuTpp592z6/3WJ8TrYMqqOu91nqv9ejnn3/eo2unXwDdFxWE/K7OKhBt2LDBfT59eq0S3fpUlE2Fcv/2A6XXpOWv7bKK7zJz5kxXWNJ2Q8+hYpQ+Nyr6armocKYfEk444QTXZVfFx2iapqL3+eefn+31BwAQQh4AAEnk2Wef1UjX3syZM/c6T4kSJbyGDRtGrm/ZsmWPeV5++WX3OJ9//vkej7148eLItJNPPtldfJMmTXLzfPTRR5ke79hjj800397ovjfddFPk+qeffuqm1a5d29u2bVtk+sMPP+ym//DDD5myaNrw4cMj03SfBg0aeOXKlfO2b9++19cR/Vz639emTRuvSpUqXnYsXLjQ3f/RRx/NNP3GG2/0ihUrFlnOt956q1e8eHFv586dXk60bdvWPf66dev2Os+bb77p5nnkkUf2+ppEr13TtSx8Wu6xdm38eQsXLuz9+eefkenffPONm969e/e9rg++Dh06ZFqOq1evdvft37+/l1MPPPBApvdv7ty57nrnzp0zzXf77be76f/73/8i05RB76m/DmVkZHiDBw+O3L57927vyCOP9Fq3bu3+9um9q1atmteqVavINGXX419zzTWZnveCCy7wSpcuvd/XoeV0zDHHxLwt1vLR5zb6sxFLrM/ykCFD3Ov8448/ItPq1avnHX744d7GjRsj06ZOneqeM/p9+uKLL9y0l156KdNjTpw4Meb0rPxlpNezN//++6+3a9euTNP03hYsWNAbNGhQZNr555+/1+W1t3Uju4466ih3P130Wb377rszZfIfd8mSJXvct0mTJt7xxx+/z8f3P4evvfbaXuepX7++d+ihh+7zvZw+fbp7nOeffz4y7amnnnLTFixYEJmmbV2ZMmXc5y4n6w8AIHzovgcACB219ok+C1/02FJqfaAzZR1//PHuek67dqh1jloP6Fd6n7p4qUXDf//73wPOrFYaau0UPTaL38oia2shtezw6T66rsGI1a0vnmrVqmUNGjRwLcV8GtBYrRPOPffcyHJWNy+dQU+tknLCf8/U+mFv/NvU0iO3aQyn6JY0ajHUrFkzN/B4IvnP36NHj0zT1WLKbxWUlVraqbWNWjPdfffdkelz5861X375xbW8UUsSfRZ00fulljOff/65684WTS1Qomnd1H1z+z3QeqNWQWrRtjfRn2VlVnZ1ZVW912/No/urdZta3EW3/FPLJLWciqbWVeqSqG5e/rLQRa3IdN9PP/30oF+XupKpNZr/edGy02Or21r09kevXy2+1IIot6kl3MSJE+3xxx+32rVru+6OyuLzuz/GOsmDujTG6h6Zm9tlteLScqlZs6ZbDtHLRS31lCF6m6tuvnqfore52Vl/AADhk9ZFKe2
|
||
|
"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",
|
||
|
" \n",
|
||
|
" # Create bar charts for input and output tokens\n",
|
||
|
" width = 0.35 # width of the bars\n",
|
||
|
" indices = range(len(df))\n",
|
||
|
" \n",
|
||
|
" plt.bar(indices, df['input_tokens'], width=width, label='Input Tokens', alpha=0.7)\n",
|
||
|
" plt.bar([i + width for i in indices], df['output_tokens'], width=width, label='Output Tokens', alpha=0.7)\n",
|
||
|
" \n",
|
||
|
" # Set labels and ticks\n",
|
||
|
" 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([i + width/2 for i in indices], [dt.strftime('%Y-%m-%d') for dt in df['start_datetime']], rotation=45)\n",
|
||
|
" 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",
|
||
|
" <th>service_tier</th>\n",
|
||
|
" </tr>\n",
|
||
|
" </thead>\n",
|
||
|
" <tbody>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>0</th>\n",
|
||
|
" <td>2024-12-16 10:46:29</td>\n",
|
||
|
" <td>2024-12-17</td>\n",
|
||
|
" <td>1734345989</td>\n",
|
||
|
" <td>1734393600</td>\n",
|
||
|
" <td>22483</td>\n",
|
||
|
" <td>15488</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>32</td>\n",
|
||
|
" <td>proj_frFrNmknEESBPFLqlnYutIA9</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>gpt-4o-2024-08-06</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>1</th>\n",
|
||
|
" <td>2024-12-16 10:46:29</td>\n",
|
||
|
" <td>2024-12-17</td>\n",
|
||
|
" <td>1734345989</td>\n",
|
||
|
" <td>1734393600</td>\n",
|
||
|
" <td>22454</td>\n",
|
||
|
" <td>4399</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>32</td>\n",
|
||
|
" <td>proj_frFrNmknEESBPFLqlnYutIA9</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>gpt-3.5-turbo-0125</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>2</th>\n",
|
||
|
" <td>2024-12-16 10:46:29</td>\n",
|
||
|
" <td>2024-12-17</td>\n",
|
||
|
" <td>1734345989</td>\n",
|
||
|
" <td>1734393600</td>\n",
|
||
|
" <td>380</td>\n",
|
||
|
" <td>848</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>24</td>\n",
|
||
|
" <td>proj_VV4ZAjd6ALfFd9uh0vY8joR1</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>gpt-4o-mini-2024-07-18</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>3</th>\n",
|
||
|
" <td>2024-12-16 10:46:29</td>\n",
|
||
|
" <td>2024-12-17</td>\n",
|
||
|
" <td>1734345989</td>\n",
|
||
|
" <td>1734393600</td>\n",
|
||
|
" <td>372</td>\n",
|
||
|
" <td>368</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>13</td>\n",
|
||
|
" <td>proj_VV4ZAjd6ALfFd9uh0vY8joR1</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>gpt-4o-2024-08-06</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>4</th>\n",
|
||
|
" <td>2024-12-16 10:46:29</td>\n",
|
||
|
" <td>2024-12-17</td>\n",
|
||
|
" <td>1734345989</td>\n",
|
||
|
" <td>1734393600</td>\n",
|
||
|
" <td>1343</td>\n",
|
||
|
" <td>1468</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>0</td>\n",
|
||
|
" <td>7</td>\n",
|
||
|
" <td>proj_L67gOme4S2nBA8aQieEOwLy7</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>gpt-4o-2024-08-06</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",
|
||
|
"0 2024-12-16 10:46:29 2024-12-17 1734345989 1734393600 22483 \n",
|
||
|
"1 2024-12-16 10:46:29 2024-12-17 1734345989 1734393600 22454 \n",
|
||
|
"2 2024-12-16 10:46:29 2024-12-17 1734345989 1734393600 380 \n",
|
||
|
"3 2024-12-16 10:46:29 2024-12-17 1734345989 1734393600 372 \n",
|
||
|
"4 2024-12-16 10:46:29 2024-12-17 1734345989 1734393600 1343 \n",
|
||
|
"\n",
|
||
|
" output_tokens input_cached_tokens input_audio_tokens \\\n",
|
||
|
"0 15488 0 0 \n",
|
||
|
"1 4399 0 0 \n",
|
||
|
"2 848 0 0 \n",
|
||
|
"3 368 0 0 \n",
|
||
|
"4 1468 0 0 \n",
|
||
|
"\n",
|
||
|
" output_audio_tokens num_model_requests project_id \\\n",
|
||
|
"0 0 32 proj_frFrNmknEESBPFLqlnYutIA9 \n",
|
||
|
"1 0 32 proj_frFrNmknEESBPFLqlnYutIA9 \n",
|
||
|
"2 0 24 proj_VV4ZAjd6ALfFd9uh0vY8joR1 \n",
|
||
|
"3 0 13 proj_VV4ZAjd6ALfFd9uh0vY8joR1 \n",
|
||
|
"4 0 7 proj_L67gOme4S2nBA8aQieEOwLy7 \n",
|
||
|
"\n",
|
||
|
" user_id api_key_id model batch service_tier \n",
|
||
|
"0 None None gpt-4o-2024-08-06 None None \n",
|
||
|
"1 None None gpt-3.5-turbo-0125 None None \n",
|
||
|
"2 None None gpt-4o-mini-2024-07-18 None None \n",
|
||
|
"3 None None gpt-4o-2024-08-06 None None \n",
|
||
|
"4 None None gpt-4o-2024-08-06 None None "
|
||
|
]
|
||
|
},
|
||
|
"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",
|
||
|
" \"start_time\": start_time, # Required: Start time (Unix seconds)\n",
|
||
|
" \"bucket_width\": \"1d\", # Optional: '1m', '1h', or '1d' (default '1d')\n",
|
||
|
" \"group_by\": [\"model\", \"project_id\"], # Group data by model and project_id\n",
|
||
|
" \"limit\": 7 # Optional: Number of buckets to return\n",
|
||
|
"}\n",
|
||
|
"\n",
|
||
|
"# Initialize an empty list to store all data\n",
|
||
|
"all_group_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_group_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_group_data:\n",
|
||
|
" print(\"Data retrieved successfully!\")\n",
|
||
|
"else:\n",
|
||
|
" print(\"Issue: No data available to retrieve.\")\n",
|
||
|
"\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",
|
||
|
" records.append({\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",
|
||
|
" \"service_tier\": result.get(\"service_tier\", \"N/A\")\n",
|
||
|
" })\n",
|
||
|
"\n",
|
||
|
"# Create a DataFrame from the records\n",
|
||
|
"df = pd.DataFrame(records)\n",
|
||
|
"\n",
|
||
|
"# Convert Unix timestamps to datetime for readability\n",
|
||
|
"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",
|
||
|
"\n",
|
||
|
"# Reorder columns for better readability\n",
|
||
|
"df = df[\n",
|
||
|
" [\n",
|
||
|
" \"start_datetime\", \"end_datetime\", \"start_time\", \"end_time\",\n",
|
||
|
" \"input_tokens\", \"output_tokens\", \"input_cached_tokens\",\n",
|
||
|
" \"input_audio_tokens\", \"output_audio_tokens\", \"num_model_requests\",\n",
|
||
|
" \"project_id\", \"user_id\", \"api_key_id\", \"model\", \"batch\", \"service_tier\"\n",
|
||
|
" ]\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": {
|
||
|
"image/png": "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
|
||
|
"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",
|
||
|
" .agg({\n",
|
||
|
" \"num_model_requests\": \"sum\",\n",
|
||
|
" })\n",
|
||
|
" .reset_index()\n",
|
||
|
")\n",
|
||
|
"\n",
|
||
|
"# Determine unique models and project IDs for plotting and color mapping\n",
|
||
|
"models = sorted(grouped_by_model_project['model'].unique())\n",
|
||
|
"project_ids = sorted(grouped_by_model_project['project_id'].unique())\n",
|
||
|
"distinct_colors = [\n",
|
||
|
" \"#1f77b4\", \"#ff7f0e\", \"#2ca02c\", \"#d62728\", \"#9467bd\",\n",
|
||
|
" \"#8c564b\", \"#e377c2\", \"#7f7f7f\", \"#bcbd22\", \"#17becf\"\n",
|
||
|
"]\n",
|
||
|
"project_color_mapping = {pid: distinct_colors[i % len(distinct_colors)] for i, pid in enumerate(project_ids)}\n",
|
||
|
"\n",
|
||
|
"# Calculate total number of requests per project_id for legend\n",
|
||
|
"project_totals = (\n",
|
||
|
" grouped_by_model_project.groupby(\"project_id\")[\"num_model_requests\"].sum()\n",
|
||
|
" .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",
|
||
|
" model_data = grouped_by_model_project[grouped_by_model_project['model'] == model]\n",
|
||
|
" \n",
|
||
|
" bottom = 0\n",
|
||
|
" # Stack segments for each project ID within the bars\n",
|
||
|
" for _, row in model_data.iterrows():\n",
|
||
|
" color = project_color_mapping[row['project_id']]\n",
|
||
|
" plt.bar(x[model_idx], row['num_model_requests'], width=bar_width,\n",
|
||
|
" bottom=bottom, color=color)\n",
|
||
|
" bottom += row['num_model_requests']\n",
|
||
|
"\n",
|
||
|
"# Labeling and styling\n",
|
||
|
"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",
|
||
|
"plt.xticks(x, models, rotation=45, ha=\"right\")\n",
|
||
|
"\n",
|
||
|
"# Create a sorted legend with totals\n",
|
||
|
"handles = [\n",
|
||
|
" mpatches.Patch(\n",
|
||
|
" color=project_color_mapping[pid],\n",
|
||
|
" label=f\"{pid} (Total: {total})\"\n",
|
||
|
" )\n",
|
||
|
" for pid, total in project_totals.items()\n",
|
||
|
"]\n",
|
||
|
"plt.legend(handles=handles, bbox_to_anchor=(1.05, 1), loc='upper left')\n",
|
||
|
"\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": {
|
||
|
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAMkCAYAAAClU0NXAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAvEFJREFUeJzs3Qd4W+X1x/Gf9x7Ze+9FEsLemwJlzzLKKnv+S2mhAzqg7BFaoGW3tMyWUfaGBEgIkITsxNl7OLEd7yHp/5wbHGzHTjwkvxrfz/OI2LJ0dSRdiXvued/zxgUCgYAAAAAAAEDQxQd/kwAAAAAAwJB0AwAAAAAQIiTdAAAAAACECEk3AAAAAAAhQtINAAAAAECIkHQDAAAAABAiJN0AAAAAAIQISTcAAAAAACFC0g0AAAAAQIiQdAMIW59++qni4uL0+9//3snj9+/f37vUZbFYTBabC8uXL/ce/4ILLlCkqq6u9l7HIUOGKCUlxXs+r732miJFsN6DQw45xNsOwl8svleuv+sAIJqQdANolwSl7iU9PV09e/bU4YcfrltuuUVLliwJyWNH6oFyY8l+NLnvvvv0hz/8wdsHfvGLX+jWW2/V8OHDd3ofez1q9585c+Y0ehufz6devXptv53te9Gk4ecoMTFR3bp1049//GN9+OGHimWR+llvbuJb95KRkaHddtvN+1tpaamixTPPPOM9P/u3Nfe78847G90nai9JSUnq1KmTxo0bp4svvljvvvuu/H5/kJ8FADQusYnrASCoBg0apHPPPdf7ubKyUhs3btS0adP0pz/9SX/+85/1y1/+Urfffnu9A+e99tpL8+fPV+fOnZ3E/NFHHyncWFJpr0lOTo4i1ZtvvqnMzEx98MEHSk5Obvb94uO3nSd+6qmndP/99+/w93feeUdr1671ktGamhpFI0sarr76au/niooKzZ07V2+99ZZ3ee655/STn/zEdYgIgVNPPVWjR4/2fl63bp3+97//eSeu3njjDU2ZMqVFn6Pmsv3srLPOUt++fRXJbrjhBu/7xhLswsJC7/vz3//+t/c9st9+++n555+P+OcIIPyRdANoF4MHD250mPjnn3+u8847T3fccYcSEhK8JLyWVcR3VQEN9YmCcGPVGpevSTBYYmzJY0sTBXvuBx10kP71r3/prrvu8n6vyw6i7WTE2LFjNWnSJEUjOwHV8HP0wgsveMn2zTffTNIdpU477TQvAa517733eiclp0+f7p1sCcV0E9vXXJ3wDCYbTdO9e/d61+Xn5+vaa6/1Eu6jjz5a33zzjTeCAABCheHlAJw64IADvGF+Nrf37rvv1qpVq3Y5pzsvL08XXnihBgwY4N2vY8eOXqJ1/fXXKxAIeLex+3322Wfbf6691B6c1p2Xa5WPk08+2UsE6w5L3tUw7yeffFJjxoxRamqqV4H+v//7PxUXFzd7XnrDucG1v69YscK71I279v47m09s97FhkxaLJbS9e/f2fl+5cuUOt60delk7v9qep72WQ4cO1SOPPKKWevrpp7X33nt7FSW72M8Nh4nWDpVdtmxZvefXkqH0F110kTZt2uRV+Oqy66yCbklnWlpam+KsO1zdkns7YWTvsf1rJ4d2NiTVRnDYfmC3tdfTkharUjY1JD4YzjzzTC9hsNfUkom67PNgJyP2339/ZWdneyey9thjD++6xmzZskWXX365N2zdbrvnnnvq1VdfbXTob0v27da+RsH4rJtPPvlExxxzjDelwbZjz+/AAw/UY4891qLX2kYX3HTTTV5l1PaJESNG6C9/+cv2WMwTTzzhPb59nzXm448/9v5+2WWXqbWysrK2P7+vv/7a+7fue2SfD3vP7XZ1P1+2f9hrV/t6du3aVWeccUajr/3O5nTPmjXLOwnQo0cP77umX79+uuaaa7R58+ZG4/3uu+90zjnneN9J9rh2vx/96EfbP8f2XOx9NvZv3fcxFGyfs5N3hx12mBYsWKCHH344JI8DALWodANwbtiwYd6B37PPPus11LKDt51VSa3CY3MZjzvuOC/hsJ/t4NySRasA2fBimydsB5+WiNjPtWw+X12LFy/WPvvs4yXPduBnB43NqcDa8GYbfm6Pb3HYnNoHH3xQU6dO9aqsDauwzZGbm+vFatsxdnBcN0nemUWLFnknMCz5PP744zVq1CjvQNqSKzuwtREFllA3ZEmqDfO3hMRGGrz00ku66qqrvPgvueSSZsVtFSNLPCzZtyTf/Pe///UOnmfMmKGJEyfWew4Nn5897+aykyMdOnTwkudTTjll+/W279gJBEvKf/e737UpzlqXXnqp9/pZgmKviSVc9r5/+eWXjW7fehPYc1y9erWOOuoonXTSSV6CaY/x3nvvefuLJfmhZPt+LUsELdGxap41rTv77LO9fduG9dvznzdvnvd5qVVWVubFP3v2bO277746+OCDvZNgto/b8wmGlrxGwfqs29B7+0zYfnbiiSd6CZ99TiwRtP3G3ufmsu8p21fsJIGxuG2/spMM1qug9jNlQ5rtpJxNm2no8ccf9/5t7udrVxompi+//LLef/99b67/lVdeqa1bt3rX23O297X2PbCk2U6A/ec///FeI3v97TtkV2xou70ONt3DXs8+ffp4+9Jf//pXbxtfffWV9xmtZa+R7Xu2P9r7YN/39p7b7ew1sutsP7Ch36+//rq3zYbf06Fg8f/mN7/xToK8+OKLjb5XABA0AQAIoWXLllkJKHD00Ufv9HZPPvmkd7vzzjtv+3WffPKJd92tt966/bqHHnrIu+7BBx/cYRubN2+u9/vBBx/s3XZncdnllltuafQ2/fr18y51WSx2n+Tk5MB33323/Xq/3x84++yzvb/de++9O30ODWM4//zzd/m4u7rPoYce6l3/97//vd71Dz/8sHf9YYcd1uhrs/feeweKioq2X79gwYJAYmJiYNiwYYHm+Oyzz7ztjBgxIlBYWLj9+i1btgSGDh3q/W3SpEnNfn5NsdunpKR4P1999dVejOvWrdv+91GjRgXGjBnj/Wz7mj2uvVatjbP2fRs7dmygpKRk+/WrV68OdO7cudH3YL/99gskJCQE3n333XrXL1y4MJCVlbU9vubsn42x2zb2vjz33HPe3+w1qOuxxx7zrr/wwgsDVVVV26+vrKwMHH/88d7fvvnmmx327UsuuaTeduz51H5Wnn766Tbt2y15jYL1WT/llFO8v82cOXOHv+Xn5weao3b79vrX3X/sZ7suLi4u8PXXX2+//oorrvBu/+mnn+4Qt+3H48aNa9bj1r4nzz//fL3ri4uLAyNHjvT+9o9//MO7zt4b+z0+Pj7wwQcf7LAt2w/s7zfffHO969966y3v+sGDBwd8Pt8Oj23vc93XKzs7O9CrV6/A8uXL623HYrTb2+ez1vr16wMZGRneZfr06TvEtGrVqu0/18Zfdx9rjtr73XHHHY2+Z3W/JxqqqKjwvkvsNauurm7R4wJASzC8HEBYsGGfpuHw2KY0NoTYhp62lM31s2pHS/30pz/1OgjXrTZZQzirFre0+25b2fBxGz47cuTIHapnNlTY5oBbNafu0P1aNlzahh3XsiqUDUtduHDhDkPlG/OPf/xj+1DUus3drNJVW3UM9uth1WxrlFb72FYxs4Zidn2w4vznP//p/Wvd9evO9bQq+XXXXbfD9q36aRXw888/35sjWpeNMLD3xSrIbR1mbp8Pew52sWHOViW0arYNlX/00Ufr3dYqjxa7DZ2tO/LCqt3WtNBYFbzuc7a//fGPf6y3HXs+ttJAW7X2NQrWZ72x7diUkpawURR19x/7+be//a1Xxa3dx2o/d7VDzeuyyro1kmxplduq0bXv+xVXXOF9Tq26bFMF6s71NlYpPuKII+pdV1VV5b3X9nwt3rqOPfZYHXnkkd6ony+++GKncdg+YpVz+96wIeV1WRy7776712Oglr0mNjrBKv/jx4/fYXs23NwlG+pur4lNGbGpFQAQKgwvBxBRLMmwhlE23NeGotq8QBsGO3DgwFZtz+aHtqbzr80HbcgOQm2opSWAdpAbio7CjZk5c6b
|
||
|
"text/plain": [
|
||
|
"<Figure size 1000x800 with 1 Axes>"
|
||
|
]
|
||
|
},
|
||
|
"metadata": {},
|
||
|
"output_type": "display_data"
|
||
|
},
|
||
|
{
|
||
|
"data": {
|
||
|
"image/png": "iVBORw0KGgoAAAANSUhEUgAABHYAAAMVCAYAAAAS9nP6AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3QV4VGf6BfAzcVcSggT34lKgBeotdaGuW3fb3dr+t+12d7v1bt2FFupGDaeUIgWKu0tC3N1G/s+57ISJkkCSm5k5v+eZlpm5mfnm3pkk9+T93s/icDgcEBERERERERERt+Nj9gBEREREREREROTIKNgREREREREREXFTCnZERERERERERNyUgh0RERERERERETelYEdERERERERExE0p2BERERERERERcVMKdkRERERERERE3JSCHRERERERERERN6VgR0RERERERETETSnYERGRJvn1119hsVjwj3/846gfq0ePHsbFm73yyis45phjEBISYuzXl156Ce2ZjtmR2bdvn3F8//SnP8FT8PWceOKJ8HYtsR/4vuDj8H0iIiJypBTsiIiYeLJX+xIaGoqhQ4fiiSeeQHFxsdnDlFby+eef495770VgYKDx/8cffxzjxo1r9Gt4AukMVpzvn4ZCtvT0dDz00EPGeyk8PNwIj/r164c77rgDO3furPdr+Fh8TAZ47dHUqVNrjM91fxzJ5y0gIACJiYm48sorsWHDBngSTw1e+Jqcx++nn35qcLuxY8dWb9de389Hiu951/exr68vYmNjccopp+Crr76CN1NIJiLezM/sAYiIeLPevXvj6quvNv7tcDiQlZWFWbNmGSfZs2fPxpIlS4xf3MWzOE9K+f/OnTu36GPPnDkTl19+OYqKioyw6Oabb4afnx/WrVuHt99+G++99x7efPNN3HjjjfDmzxuD0+XLl+Ozzz7Dt99+iwULFuD4449v8efs0qULtm7disjIyBZ/bG/F9/MHH3yAc845p859mzdvxsqVK41trFYrPBF/Jvz97383/l1VVYVdu3bhu+++wy+//IL//Oc/eOSRR8weooiItDEFOyIiJurTp0+dqouKigqMHz/eOOlctGgRTj75ZNPGJ60jNTXV+H9LhzqrV6/GRRddBB8fH8yYMQPnn39+jft///13nHfeeUbYk5CQgLPPPhve/nnjCfKTTz6J//u/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
|
||
|
"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",
|
||
|
" records.append({\n",
|
||
|
" \"project_id\": result.get(\"project_id\", \"N/A\"),\n",
|
||
|
" \"num_model_requests\": result.get(\"num_model_requests\", 0),\n",
|
||
|
" })\n",
|
||
|
"\n",
|
||
|
"# Create a DataFrame\n",
|
||
|
"df = pd.DataFrame(records)\n",
|
||
|
"\n",
|
||
|
"# Aggregate data by project_id\n",
|
||
|
"grouped_by_project = (\n",
|
||
|
" df.groupby(\"project_id\")\n",
|
||
|
" .agg({\"num_model_requests\": \"sum\"})\n",
|
||
|
" .reset_index()\n",
|
||
|
")\n",
|
||
|
"\n",
|
||
|
"# Visualize Pie Chart\n",
|
||
|
"if not grouped_by_project.empty:\n",
|
||
|
" # Filter out rows where num_model_requests == 0\n",
|
||
|
" filtered_grouped_by_project = grouped_by_project[grouped_by_project['num_model_requests'] > 0]\n",
|
||
|
" \n",
|
||
|
" # Calculate the total model requests after filtering\n",
|
||
|
" total_requests = filtered_grouped_by_project['num_model_requests'].sum()\n",
|
||
|
" \n",
|
||
|
" if total_requests > 0:\n",
|
||
|
" # Calculate percentage of total for each project\n",
|
||
|
" filtered_grouped_by_project['percentage'] = (\n",
|
||
|
" filtered_grouped_by_project['num_model_requests'] / total_requests\n",
|
||
|
" ) * 100\n",
|
||
|
" \n",
|
||
|
" # Separate \"Other\" projects (below 5%)\n",
|
||
|
" other_projects = filtered_grouped_by_project[filtered_grouped_by_project['percentage'] < 5]\n",
|
||
|
" main_projects = filtered_grouped_by_project[filtered_grouped_by_project['percentage'] >= 5]\n",
|
||
|
" \n",
|
||
|
" # Sum up \"Other\" projects\n",
|
||
|
" if not other_projects.empty:\n",
|
||
|
" other_row = pd.DataFrame({\n",
|
||
|
" \"project_id\": [\"Other\"],\n",
|
||
|
" \"num_model_requests\": [other_projects['num_model_requests'].sum()],\n",
|
||
|
" \"percentage\": [other_projects['percentage'].sum()]\n",
|
||
|
" })\n",
|
||
|
" filtered_grouped_by_project = pd.concat([main_projects, other_row], ignore_index=True)\n",
|
||
|
" \n",
|
||
|
" # Sort by number of requests for better legend organization\n",
|
||
|
" filtered_grouped_by_project = filtered_grouped_by_project.sort_values(by=\"num_model_requests\", ascending=False)\n",
|
||
|
" \n",
|
||
|
" # Main pie chart for distribution of model requests by project_id\n",
|
||
|
" plt.figure(figsize=(10, 8))\n",
|
||
|
" plt.pie(\n",
|
||
|
" 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",
|
||
|
" startangle=140,\n",
|
||
|
" textprops={'fontsize': 10}\n",
|
||
|
" )\n",
|
||
|
" plt.title('Distribution of Model Requests by Project ID', fontsize=14)\n",
|
||
|
" plt.axis('equal') # Equal aspect ratio ensures pie chart is circular.\n",
|
||
|
" plt.tight_layout()\n",
|
||
|
" plt.show()\n",
|
||
|
" \n",
|
||
|
" # If there are \"Other\" projects, generate a second pie chart for breakdown\n",
|
||
|
" if not other_projects.empty:\n",
|
||
|
" other_total_requests = other_projects['num_model_requests'].sum()\n",
|
||
|
" \n",
|
||
|
" plt.figure(figsize=(10, 8))\n",
|
||
|
" plt.pie(\n",
|
||
|
" 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",
|
||
|
" startangle=140,\n",
|
||
|
" textprops={'fontsize': 10}\n",
|
||
|
" )\n",
|
||
|
" plt.title('Breakdown of \"Other\" Projects by Model Requests', fontsize=14)\n",
|
||
|
" plt.axis('equal') # Equal aspect ratio ensures pie chart is circular.\n",
|
||
|
" 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": [
|
||
|
"Costs data retrieved successfully!\n"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"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",
|
||
|
"# Initialize an empty list to store all data\n",
|
||
|
"all_costs_data = []\n",
|
||
|
"\n",
|
||
|
"# Initialize pagination cursor\n",
|
||
|
"page_cursor = None\n",
|
||
|
"\n",
|
||
|
"# Loop to handle pagination\n",
|
||
|
"while True:\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",
|
||
|
" }\n",
|
||
|
"\n",
|
||
|
" if page_cursor:\n",
|
||
|
" costs_params[\"page\"] = page_cursor\n",
|
||
|
"\n",
|
||
|
" costs_response = requests.get(costs_url, headers=headers, params=costs_params)\n",
|
||
|
"\n",
|
||
|
" if costs_response.status_code == 200:\n",
|
||
|
" costs_json = costs_response.json()\n",
|
||
|
" all_costs_data.extend(costs_json.get(\"data\", []))\n",
|
||
|
"\n",
|
||
|
" page_cursor = costs_json.get(\"next_page\")\n",
|
||
|
" if not page_cursor:\n",
|
||
|
" break\n",
|
||
|
" else:\n",
|
||
|
" print(f\"Error: {costs_response.status_code}\")\n",
|
||
|
" break\n",
|
||
|
"\n",
|
||
|
"if all_costs_data:\n",
|
||
|
" print(\"Costs data retrieved successfully!\")\n",
|
||
|
"else:\n",
|
||
|
" print(\"No costs data found.\")\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"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",
|
||
|
"execution_count": 11,
|
||
|
"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",
|
||
|
" <td>1734307200</td>\n",
|
||
|
" <td>1734393600</td>\n",
|
||
|
" <td>55.358578</td>\n",
|
||
|
" <td>usd</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>2024-12-16</td>\n",
|
||
|
" <td>2024-12-17</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>1</th>\n",
|
||
|
" <td>1734393600</td>\n",
|
||
|
" <td>1734480000</td>\n",
|
||
|
" <td>0.000110</td>\n",
|
||
|
" <td>usd</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>2024-12-17</td>\n",
|
||
|
" <td>2024-12-18</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>2</th>\n",
|
||
|
" <td>1734480000</td>\n",
|
||
|
" <td>1734566400</td>\n",
|
||
|
" <td>0.016204</td>\n",
|
||
|
" <td>usd</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>2024-12-18</td>\n",
|
||
|
" <td>2024-12-19</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>3</th>\n",
|
||
|
" <td>1734566400</td>\n",
|
||
|
" <td>1734652800</td>\n",
|
||
|
" <td>2.121425</td>\n",
|
||
|
" <td>usd</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>2024-12-19</td>\n",
|
||
|
" <td>2024-12-20</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>4</th>\n",
|
||
|
" <td>1734652800</td>\n",
|
||
|
" <td>1734739200</td>\n",
|
||
|
" <td>3.771420</td>\n",
|
||
|
" <td>usd</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>None</td>\n",
|
||
|
" <td>2024-12-20</td>\n",
|
||
|
" <td>2024-12-21</td>\n",
|
||
|
" </tr>\n",
|
||
|
" </tbody>\n",
|
||
|
"</table>\n",
|
||
|
"</div>"
|
||
|
],
|
||
|
"text/plain": [
|
||
|
" start_time end_time amount_value currency line_item project_id \\\n",
|
||
|
"0 1734307200 1734393600 55.358578 usd None None \n",
|
||
|
"1 1734393600 1734480000 0.000110 usd None None \n",
|
||
|
"2 1734480000 1734566400 0.016204 usd None None \n",
|
||
|
"3 1734566400 1734652800 2.121425 usd None None \n",
|
||
|
"4 1734652800 1734739200 3.771420 usd None None \n",
|
||
|
"\n",
|
||
|
" start_datetime end_datetime \n",
|
||
|
"0 2024-12-16 2024-12-17 \n",
|
||
|
"1 2024-12-17 2024-12-18 \n",
|
||
|
"2 2024-12-18 2024-12-19 \n",
|
||
|
"3 2024-12-19 2024-12-20 \n",
|
||
|
"4 2024-12-20 2024-12-21 "
|
||
|
]
|
||
|
},
|
||
|
"execution_count": 11,
|
||
|
"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",
|
||
|
" cost_records.append({\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",
|
||
|
"# 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": "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.\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 12,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAJOCAYAAABm7rQwAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAVoxJREFUeJzt3QecVNXdP/6zSBXpIogCYkGwoIgNNbGhxChKRKPGJzassWJ8VOzYMJoYSyxJNBITjVFj12jsFUXFrmBDJSIqKl1AYf6vc57/7G93GJRdlzu7s+/36zXs7r2zM2fnfvey9zOnVORyuVwAAAAAgAw1yfLJAAAAACASSgEAAACQOaEUAAAAAJkTSgEAAACQOaEUAAAAAJkTSgEAAACQOaEUAAAAAJkTSgEAAACQOaEUAAAAAJkTSgFAI/fYY4+FioqK9JHG4eabbw4dO3YMs2fPLnVTqIUvvvgitG7dOtx3332lbgoA/CBCKQAogRgCLc1taYKi888/P9xxxx0hK++991447LDDwuqrrx5atmwZ2rZtG7bccstw6aWXhq+//rrOn2/u3LnhrLPOalCh2ZgxY6odx/g6devWLQwePDhcdtllYdasWSVr28KFC8OZZ54Zjj766LDCCitUbl9ttdXCLrvsklk7rrzyyvQ6La0RI0aEjTbaKIVpyy+/fOjbt2+qi2LB2vz588NJJ52UXvNWrVqFzTbbLDz44INL9TwHHHBAtWMXX6NY63vssUf417/+FRYtWhRKrVOnTuHggw8Op59+eqmbAgA/SNMf9u0AQG387W9/q/b19ddfny6aC7fHC++lCaXiBfPQoUPDsnbvvfeGPffcM7Ro0SLst99+Yb311gsLFiwITz31VPjf//3f8MYbb4Q//elPdR5KjRo1Kn2+zTbbhIbk7LPPDr169QrffPNNmDp1agrWjjvuuHDxxReHu+66K/Tr1y/zNt19991h4sSJ4dBDDw2lFEOpFVdcMYVAS+P5558PP/rRj8KBBx6YQr6XXnopXHDBBeGhhx4KTzzxRGjS5P+91xof89Zbb02v9VprrZXCr5/+9Kfh0UcfDVtttdX3Ples72uuuSZ9HoPWDz/8ML1u8fcs1uCdd96ZwthSOvzww1PA+cgjj4TtttuupG0BgNoSSgFACfzP//xPta+fffbZFEoVbq9PJk2aFPbee+/Qs2fPdCG88sorV+478sgjw7vvvptCq8Zizpw5aQjVd9lpp53CxhtvXPn1yJEj02sXeyTtuuuu4a233ko9ebJ03XXXpZ5tq6yySmhIYvBZaI011ggnnHBCGDduXNh8883Ttvj5TTfdFC666KK0L8oHqCeeeGJ45plnvve5mjZtutjv4rnnnptCsHgMDznkkPDPf/4zlFIMrOPPFAM3oRQADZXhewBQj0OPX//616F79+6p58baa68dfvvb34ZcLld5nzi8KN7vr3/9a+Vwo3zPk9i741e/+lX6vhh8xCE/sZfTBx98UKv2XHjhhWmo1LXXXlstkMpbc801w7HHHlv59bfffhvOOeecFBzE9sfhYaecckoaWlXVCy+8kIa1xV4zsZ2xZ9FBBx2U9sW2du7cOX0ee0vlf8Y4bOv7hs7F3jNxmGH8uWOvlhhMfPXVV4vd/9///nfqgRMDpjZt2oSdd9459fiqKr6mcRhXHLoYe9zE++277761eBVDChDisKt4fP7+979Xbn/11VfT8+SHRXbt2jW9DnH+oLzY0yf+bLfffvtij3vjjTemfWPHjl3ic8+bNy/cf//9YdCgQbVq+5NPPplqqEePHumYxtqMw+oKh23GXmGxR9Oqq66a7hfrZbfddqusvVgL8TV+/PHHK49pbXrBxceJpk+fXrkt9pBabrnlqvUEi6/n8OHD02szefLkUFsnn3xy2HHHHcMtt9wS3n777crtsedUrJs4XDD+vLHmY+3HoZJ5cchks2bNwueff77Y48a2tm/fPh2f7/udqGqHHXZIPbiqnhMAoCHRUwoA6qF4kRl70sQQIl5Mb7jhhuGBBx5IQ+Q+/vjj8Pvf/z7dLw73i3PLbLrpppUX4fGCOD/cKfYKib2bYjgQA4GrrroqXfy/+eabaV6emogXvzEw2WKLLZbq/rFdMSyLQ55iuPbcc8+F0aNHp95B+VDls88+Sxf5MXiKF/zxwjy287bbbkv74/bY5iOOOCL87Gc/C7vvvnvavjTD3o466qj0eDHAisPV4uPEICg/sXv+9dt///1TAPCb3/wmDRWM94tDvOLwsHzokQ/Z4v3ivhgO1vT1q+qXv/xlCuj+85//pF43Uewp9/7776cwJwZS+aGQ8WPsSZcPbmIQdMMNN6TXo6q4LR77gQMHLvF5X3zxxTTcMs7NVBsxjImvUTweMeyLvZIuv/zy8N///jftyxs2bFhqd5y3Kr6G8TjHn++jjz5KX19yySWVc1qdeuqp6Xu6dOnyvc8fj0EMoOLP8Prrr4fTTjstBYSx/vPicevdu/diw+vy93n55ZfTa/hDjl08bvHnic+TD0Ljz3L88cenj7E33BlnnBFmzpyZemzlvy8O54w9rGJt5sWfJQZp8TWL4dn3/U5UNWDAgHQuiK917DUFAA1ODgAouSOPPDJ2daj8+o477khfn3vuudXut8cee+QqKipy7777buW21q1b5/bff//FHnPu3LmLbRs7dmx63Ouvv75y26OPPpq2xY9LMmPGjHSf3Xbbbal+npdffjnd/+CDD662/YQTTkjbH3nkkfT17bffnr5+/vnnl/hYn3/+ebrPmWeeuVTPfd1116X7DxgwILdgwYLK7RdeeGHafuedd6avZ82alWvfvn3ukEMOqfb9U6dOzbVr167a9vj6xu89+eSTa9SG7/q54nP079//O4/XP/7xj/Q4TzzxROW2kSNH5lq0aJGbPn165bbPPvss17Rp0+99ja655pr0eK+99tpi+3r27Jnbeeedv/P7i7Vx9OjRqSY//PDD9PVXX32VnuOiiy76zsdad911c1tvvXWuJvL1m7+tvfbai9VtfNzttttuse9944030vdcffXV3/kc8VjH36kleemll9LjjBgx4jtfl8MOOyy3/PLL5+bNm1e5beDAgbnNNtus2v1uu+22ar9/S/M7kffMM8+k+/7zn//83vsCQH1k+B4A1ENxqfc4BOmYY46ptj32OIq9qOKQs+9Tda6iONF2HAYWh9jFnhfjx4+vUXtij48o9kpZ2vZHsedIYfuj/NxTsS3RPffck9pYl2LPsThcKi/27olzBeXbFnu6xF43++yzT5g2bVrlLb7ucbW22EutUHyMuhJ71FRdha/q8YrDuGJb8vMkVT1ecRhiHAIZe9fkxd43sRfR981Jlh8K2KFDh1q1uWob47DR2MbYcy7WZOyhlL9P8+bNU4+0YsMlf4h11lknHbe42mScHyoOuSxcfS8OJYxD6ArFXkj5/T9EfsXCJR27uD2+LnFIaOxVNmHChGrHLvYYjMNAq/Zwiz23tt566xr/TuSPY3w+AGiIhFIAUA/FYWZxfprCECi/Gl/c/33ixXccQpSfkyrOTxOHBMUgZsaMGTVqT34oVNUL8e9rf1wNLYZgVcVhafGiO9/+eCEehy3F+aJi++K8Q3Ei7sJ5p2ojrrpWGCbEuY3y8xq98847lXM8xdel6i0Oz4rDqKqKgVYcBllXYphS9fh++eWXaU6uOIwthhyxHXEuoajq8erTp0/YZJNNUpiRFz+PAVbh670ktZ2DKA6/i/NedezYMb2esY35MCXfxlhrcShkDE7jz/LjH/84zUcW55n6oWIdxvmwYp3E54ghZ/z8lVdeqbxPfO2K1U9+vqYfOrF8PgSreuzi8Lk4nLJdu3apjfF1yQeEVY/dXnvtlV6f/LGL+2L4FOcnyw8prcnvRP445r8XABoac0oBQJmKc/bEi9njjjsuzTMUL5jjxWucY2rRokU1eqx4oR1DsjiPT01838Vy3B97/MQ5k+KcVXHerDih8+9+97u0Ld8rZVnIvwZxXqkYlhWKIVRVMUyIQVtdiHMwxUCiaoj085//PM0BFucNi3OIxZ8
|
||
|
"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 sum the amounts\n",
|
||
|
" cost_per_day = cost_df.groupby('date')['amount_value'].sum().reset_index()\n",
|
||
|
" \n",
|
||
|
" # Plot the data\n",
|
||
|
" plt.figure(figsize=(12, 6))\n",
|
||
|
" plt.bar(cost_per_day['date'], cost_per_day['amount_value'], width=0.6, color='skyblue', alpha=0.8)\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": [
|
||
|
"## 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": {
|
||
|
"display_name": ".venv",
|
||
|
"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",
|
||
|
"version": "3.13.0"
|
||
|
}
|
||
|
},
|
||
|
"nbformat": 4,
|
||
|
"nbformat_minor": 2
|
||
|
}
|