I have the token usage tied to the user in the DB. I’m talking about a bridge that removes me as the middleman. Because Stripe charges about 3%, so I would have to charge a minimum of 3% of total token usage of the user just to break even. I’d rather only have to charge like a monthly subscription fee to use my product.

1 Like

Is there a way to track the usage of each API key generated?
I need to keep track of usage by API key used by different projects.

4 Likes

I wrote a command line tool using nodejs, ref: https://community.openai.com/t/use-cli-to-batch-download-the-usage-data-of-openai-api/127734

Note that the usage data given by openai may exceed expectations. For example, I saw a message about using 152k tokens last month. Someone explained it here, but it is still very strange. ref: https://community.openai.com/t/what-is-n-context-tokens-total-why-is-it-so-large/127420

1 Like

I also need something like this. Tracking usage with each key would be very helpful.

2 Likes

Is there any progress on python scripts? Why OpenAI couldn’t simply present a user chart for organization owner in the website to track per user usage?

3 Likes

Been tracking this conversation because I’m having the same problem. Made a quick tool I call: Token Chihuahua :dog2:
The loyal watchdog your team needs to track API costs.

A simple Usage tool with per account filters. Try it out. Let me know what you need to make life easier.

Hello @boyu.niu and everyone else!

Apologies with the late reply. I will take a look either tonight or tomorrow night to see how to make the script work again, as well as write it so it works in Python, Bash, and PowerShell.

Regarding the Python script version, I could also quickly make out a GUI to allow for broader accessibility to tracking individual usage with the script.

2 Likes

I wish I can give you 1000 stars if you open-source them

Hello
Do you have the latest script that can check user usage?

I used the above script and he reported an error. Has the OpenAI backend been unable to view the usage of each user recently

Hello
Do you have the latest script that can check user usage?

I used the above script and he reported an error. Has the OpenAI backend been unable to view the usage of each user recently

I played around with LLM.REPORT after seeing this tweet.

You could use a different key per agency/org and track usage that way.

1 Like

If you’ve made an organization, I made a script that computes the per day and per month cost of each user in your org. I can’t paste the link yet, so here’s the script (from usage.py in github/dav-ell/toktrack):

import json
import requests
import datetime
from dateutil.relativedelta import relativedelta

# Read config.json
with open("config.json", "r") as f:
    config = json.load(f)

openai_org_id = config["openai_org_id"]
openai_api_key = config["openai_api_key"]

first_day_of_month = datetime.date.today().replace(day=1)
current_day = datetime.date.today()

prompt_token_cost = 0.03
completion_token_cost = 0.06

headers = {
    "method": "GET",
    "authority": "api.openai.com",
    "scheme": "https",
    "path": f"/v1/organizations/{openai_org_id}/users",
    "authorization": f"Bearer {openai_api_key}",
}

users_response = requests.get(f"https://api.openai.com/v1/organizations/{openai_org_id}/users", headers=headers)
users = users_response.json()["members"]["data"]

for user in users:
    id_of_user = user["user"]["id"]
    total_context_tokens = 0
    total_generated_tokens = 0

    daily_costs = {}  # Dictionary to store daily costs

    current_date = first_day_of_month
    while current_date <= current_day:
        usage_headers = {
            "method": "GET",
            "authority": "api.openai.com",
            "authorization": f"Bearer {openai_api_key}",
            "openai-organization": openai_org_id,
        }
        usage_response = requests.get(f"https://api.openai.com/v1/usage?date={current_date}&user_public_id={id_of_user}", headers=usage_headers)
        user_data = usage_response.json()

        context_tokens = sum([entry["n_context_tokens_total"] for entry in user_data["data"]])
        generated_tokens = sum([entry["n_generated_tokens_total"] for entry in user_data["data"]])
        total_context_tokens += context_tokens
        total_generated_tokens += generated_tokens

        # Calculate daily cost and store it in the dictionary
        daily_cost = (context_tokens * prompt_token_cost / 1000) + (generated_tokens * completion_token_cost / 1000)
        daily_costs[current_date.strftime("%Y-%m-%d")] = daily_cost

        current_date += relativedelta(days=1)

    email = user["user"]["email"]

    total_cost = (total_context_tokens * prompt_token_cost / 1000) + (total_generated_tokens * completion_token_cost / 1000)

    user_json = user["user"].copy()
    user_json["usage"] = user_data
    user_json["total_cost"] = total_cost
    user_json["daily_costs"] = daily_costs  # Add daily costs to the JSON

    user_name = user["user"]["name"].replace(" ", "_")
    with open(f"{user_name}.json", "w") as f:
        json.dump(user_json, f)

Generates a JSON file for each user within an organization with output like this:

{
    "object": "user",
    "id": "user-<id>",
    "name": "<name>",
    "email": "<email>",
    "picture": "<url>",
    "usage": {
        "object": "list",
        "data": [
            {
                "aggregation_timestamp": "<timestamp>",
                "n_requests": 1,
                "operation": "completion",
                "snapshot_id": "gpt-4-0314",
                "n_context": 1,
                "n_context_tokens_total": 1584,
                "n_generated": 1,
                "n_generated_tokens_total": 156
            },
            {
                "aggregation_timestamp": "<timestamp>",
                "n_requests": 1,
                "operation": "completion",
                "snapshot_id": "gpt-4-0314",
                "n_context": 1,
                "n_context_tokens_total": 1638,
                "n_generated": 1,
                "n_generated_tokens_total": 458
            },
            {
                "aggregation_timestamp": "<timestamp>",
                "n_requests": 1,
                "operation": "completion",
                "snapshot_id": "gpt-4-0314",
                "n_context": 1,
                "n_context_tokens_total": 415,
                "n_generated": 1,
                "n_generated_tokens_total": 287
            }
        ],
        "ft_data": [],
        "dalle_api_data": [],
        "whisper_api_data": [],
        "current_usage_usd": 0.0
    },
    "total_cost": 1.8453899999999999,
    "daily_costs": {
        "2023-06-01": 0.68382,
        "2023-06-02": 0.06273,
        "2023-06-03": 0.053279999999999994,
        "2023-06-04": 0.0,
        "2023-06-05": 0.13208999999999999,
        "2023-06-06": 0.7503,
        "2023-06-07": 0.16316999999999998
    }
}
1 Like

Thanks to this thread I was able to understand how to access usage data outside of the management portal (which was giving me a lot of rate-limit pain). I couldn’t find an exact solution for what I needed so I created a set of python scripts to accomplish this task. The code is freely available here for anyone who needs it.

It seems I am not allowed to post links so it can be found at github / stevenrick / openai_usage

It downloads usage across an org for a given date range (or yesterday if you don’t specify) and also can map the model used to their individual cost and generate plots for each user’s usage. Contributions welcome!

This code used to work for me before. But now when I run it, I get this error. Did OpenAI change their policy on how many requests we can make per min? Is anyone else getting the same error?

Error:

{'error': {'message': "You've exceeded the 5 request/min rate limit, please slow down and try again.", 'type': 'invalid_request_error', 'param': None, 'code': 'rate_limit_exceeded'}}

These are undocumented APIs, so no real guarantee that they’ll work or that OpenAI may purposefully or inadvertently add more restrictions to them.

1 Like

Hi, I have mixed the toktrack from @davell with the cost details idea from Sebastian Shepard ( Handling OpenAI API Cost Retrieval Changes - at jeypop) to get this alternative:

import json
import requests
import datetime
from dateutil.relativedelta import relativedelta
import os

import pandas as pd

import time

openai_org_id = os.getenv('ORG_ID')
openai_api_key = os.getenv('OPENAI_API_KEY')

first_day_of_month = datetime.date(2023,7,1) #start date
current_day = datetime.date.today() #end date

headers = {
    "method": "GET",
    "authority": "api.openai.com",
    "scheme": "https",
    "path": f"/v1/organizations/{openai_org_id}/users",
    "authorization": f"Bearer {openai_api_key}",
}

users_response = requests.get(f"https://api.openai.com/v1/organizations/{openai_org_id}/users", headers=headers)
users = users_response.json()["members"]["data"]

df_costs = pd.DataFrame()

for user in users:
  
    id_of_user = user["user"]["id"]

    current_date = first_day_of_month
    
    while current_date <= current_day:
        
        # we can get 5 requests per min, so I set 1 request per 15s just to make sure
        
        start = time.time()
        
        usage_headers = {
            "method": "GET",
            "authority": "api.openai.com",
            "authorization": f"Bearer {openai_api_key}",
            "openai-organization": openai_org_id,
        }
        
        usage_response = requests.get(f"https://api.openai.com/v1/usage?date={current_date}&user_public_id={id_of_user}", headers=usage_headers)
        user_data = usage_response.json()
     
        if len(user_data['data'])==0:
            
            current_date += relativedelta(days=1)
            
            end = time.time()
            
            if end - start < 15:
                time.sleep(15 - (end - start))
                
            continue
            
        else:
            usage_data = user_data["data"]
            whisper_data = user_data["whisper_api_data"]

            data = usage_data + whisper_data

            df = pd.DataFrame(data)
            df['local_timestamp'] = df['aggregation_timestamp'].apply(lambda x: datetime.datetime.fromtimestamp(x))
            # converting to openai tz
            df['system_timestamp'] = df['local_timestamp'].dt.tz_localize('America/Sao_Paulo').dt.tz_convert("UTC")
            df['user'] = user["user"]["name"].lower().replace(" ", "_")
            df['email'] = user["user"]["email"]

            df_costs = pd.concat([df_costs,df])

            current_date += relativedelta(days=1)

            end = time.time()
        
            if end - start < 15 :
                time.sleep(15 - (end - start))
                    
# model costs

model_costs = {
    "gpt-3.5-turbo": {"context": 0.0015, "generated": 0.002},
    "gpt-3.5-turbo-0301": {"context": 0.0015, "generated": 0.002},
    "gpt-3.5-turbo-0613": {"context": 0.0015, "generated": 0.002},
    "gpt-3.5-turbo-16k": {"context": 0.003, "generated": 0.004},
    "gpt-3.5-turbo-16k-0613": {"context": 0.003, "generated": 0.004},
    "gpt-4": {"context": 0.03, "generated": 0.06},
    "gpt-4-0314": {"context": 0.03, "generated": 0.06},
    "gpt-4-0613": {"context": 0.03, "generated": 0.06},
    "gpt-4-32k": {"context": 0.06, "generated": 0.12},
    "gpt-4-32k-0314": {"context": 0.06, "generated": 0.12},
    "gpt-4-32k-0613": {"context": 0.06, "generated": 0.12},
    "text-embedding-ada-002-v2": {"context": 0.0001, "generated": 0},
    "text-davinci:003": {"context": 0.03, "generated": 0.12},
    "whisper-1": {"context": 0.006 / 60, "generated": 0}, 
}

mc = pd.DataFrame(model_costs)
mc = mc.T.reset_index()

# cost calculation

df_costs=df_costs.merge(mc, left_on='snapshot_id', right_on='index', how='left')
df_costs['context_costs']=(df_costs['n_context_tokens_total']/1000)*df_costs['context']
df_costs['generated_costs']=(df_costs['n_generated_tokens_total']/1000)*df_costs['generated']
df_costs['total_costs']=df_costs['context_costs']+df_costs['generated_costs']

# saving a json file
    
with open(f"openai_costs_{first_day_of_month}_to_{current_date}.json", "w") as f:
    json.dump(df_costs.to_json(index=False, orient='table'), f)


# cost summary

def summary_costs(x):
    names = {
        'requests': x['n_requests'].sum()
        , 'context_tokens': x['n_context_tokens_total'].sum()
        , 'generated_tokens': x['n_generated_tokens_total'].sum()
        , 'context_costs': x['context_costs'].sum()
        , 'generated_costs': x['generated_costs'].sum()
        , 'total_costs': x['total_costs'].sum()
    }
    
    return pd.Series(names, index=['requests'
                                   , 'context_tokens'
                                   , 'generated_tokens'
                                   , 'context_costs'
                                   , 'generated_costs'
                                   , 'total_costs'
                                  ])

df_costs.groupby(['user', pd.Grouper(key='system_timestamp', freq='D'),'snapshot_id', 'operation']).apply(summary_costs)

# costs by day

df_costs.groupby([pd.Grouper(key='system_timestamp', freq='D')]).apply(summary_costs)

#costs by user

df_costs.groupby(['user']).apply(summary_costs).sort_values('total_costs', ascending=False)

1 Like

I have your code running, but it has been over 4 minutes and still just running. How long should it take. I have no one but myself in my Org. I am running it on google colab notebook.

Also is there a way to get current usage or current months usage?

You should be tracking this info on your end, not scraping OAI servers.

1 Like

Hi @moltra
Got the notification of you question just today.
Try running it for just one day to see what happens.
Depending on the time you have specified and the amount of customers, it should take longer (due to the time sleeper that I have included - because of api requests limit)
I have made some updates in the code.
Please check my github user bruno-curta.
project: /bruno-curta/openai-costs-tracking

The daily API has a strict 5 RPM (!) limit, so the pause between one day and the other should be at least 12 seconds apart.

I built a small UI tool using Streamlit so people can more easily manage the download over a longer time period. It also automatically compiles a CSV from the data.

Mind you, due to the 5 RPM limit, a data query across longer timespan - say a month - will take some time. There is a progress bar I implemented to give you feedback on the progress.

https://www.openaitools.io - you can also check out the source code which is linked on the site.

In the future I will also update the app with more features, like an UI to manage your ChatGPT custom model finetuning jobs etc.

2 Likes