B4J Code Snippet OpenAI usage statistics

Hi all,
I'm having some fun in building a personal assistant based on OpenAI's ChatGPT4.
The following snippet could be handy to meter tokens usage as seen on the Dashboard kindly provided by OpenAI. Although mine is a WIP (work in progress), everything seems to work correctly so here it is. Please amend it if needed and post your corrections on a new Thread (then I will modify the code below in order to have the amended snippet here)

Note: the AdminKey is not the same as the Project Key. You have to generate it on your OpenAI's reserved area once logged in

B4X:
Sub Class_Globals
    'Private fx As JFX
    Private GPT_ProjectKey As String = '<your Project Key>
    Private GPT_OrgKey As String = '<your Organization Key>
    Private GPT_ProjectID As String = '<your Project ID>
    Private GPT_AdminKey As String = '<your Admin Key>
    Public verbose As Boolean = True 'used to show Logs
End Sub

Public Sub Initialize(ShowLogs As Boolean)
    verbose = ShowLogs
End Sub

Public Sub QueryUsage(start_time As Long, end_time As Long) As ResumableSub
    Dim Tot_itk As Long     'total input tokens
    Dim Tot_otk As Long        'total number of output token
    Dim Tot_mdr As Long        'total number of model requests
    
    Dim q_string As String
    'q_string = $"start_time=${start_time}&end_time=${end_time}&bucket_width=1h&limit=24"$    'by the hour
    q_string = $"start_time=${start_time}&end_time=${end_time}&bucket_width=1d&limit=31"$    'by the day
    Wait For (MakeQueryUsage(q_string)) Complete (res As Map)
    If res.Get("success") Then
        'Totals from first page of data
        Tot_itk = res.get("itk")
        Tot_otk = res.get("otk")
        Tot_mdr = res.get("mdr")
        'check if there are any other pages and loop on them
        Dim continua As Boolean = (res.Get("success") And res.Get("more"))
        'Eventual pagination
        Do While continua
            If verbose Then LogColor("******pagination******", 0xFF0000FF)
            Dim pstring As String = $"start_time=${start_time}&end_time=${end_time}&bucket_width=1d&limit=31&page=${res.Get("np")}"$
            Wait For (MakeQueryUsage(pstring)) Complete (res2 As Map)
            'Adding to totals freom currente page
            Tot_itk = Tot_itk + res2.get("itk")
            Tot_otk = Tot_otk + res2.get("otk")
            Tot_mdr = Tot_mdr + res2.get("mdr")
            continua = (res2.Get("success") And res2.Get("more"))
        Loop 
    End If
    
    'Grand Totals for the whole periood
    Dim gtotals As Map
    gtotals.Initialize
    gtotals.Put("itk", Tot_itk)
    gtotals.Put("otk", Tot_otk)
    gtotals.Put("mdr", Tot_mdr)
    
    Return gtotals
End Sub

'Call API completions endpoint
Private Sub MakeQueryUsage(param As String) As ResumableSub
    Dim usage As Map
    usage.Initialize
    
    Dim req As HttpJob
    req.Initialize("", Me)
    req.Download("https://api.openai.com/v1/organization/usage/completions?"&param)
    req.GetRequest.SetHeader("Authorization", "Bearer " & GPT_AdminKey)
    req.GetRequest.SetHeader("Content-Type", "application/json")
    
    Wait For (req) JobDone(req As HttpJob)
    If req.Success Then
        usage = ParseJUsage(req.GetString)
        usage.Put("success", True)
        If verbose Then 
            If verbose Then Log(req.GetString)
            Log($"Total Input Tokens in page: ${usage.Get("itk")}"$)
            Log($"Total Output Tokens in page: ${usage.Get("otk")}"$)
            Log($"Total Model Requests in page: ${usage.Get("mdr")}"$)
        End If
        
    Else
        If verbose Then Log( "ERROR: " & req.ErrorMessage)
        usage.Put("success", False)
        usage.Put("error", req.ErrorMessage)
    End If
    req.Release
    
    Return usage
End Sub

'Parse an  Usage JSON string
Private Sub ParseJUsage(json As String) As Map
    Dim Tot_itk As Long     'total input tokens in a given page
    Dim Tot_otk As Long        'total number of output token in a given page
    Dim Tot_mod As Long        'total number of model requests in a given page
    
    Dim parser As JSONParser
    parser.Initialize(json)
    Dim root As Map
    root = parser.NextObject
    
    Dim jobject As String  = root.Get("object")                    'page
    'Buckets in page
    Dim jdata As List = root.Get("data")
    For j = 0 To jdata.Size-1
        'start time
        Dim m1 As Map = jdata.Get(j)
        Dim Ustime As Long = m1.Get("start_time")
        Dim Tstime As Long = DateUtils.UnixTimeToTicks(Ustime)
        'end time
        Dim Uetime As Long = m1.Get("end_time")
        Dim Tetime As Long = DateUtils.UnixTimeToTicks(Uetime)
        If verbose Then
            Log($"Bucket start time: ${DateTime.Date(Tstime)}"$)
            Log($"Bucket end time: ${DateTime.Date(Tetime)}"$)
        End If
        ' Count token from a bucket
        Dim jresults As List = m1.Get("results")
        For k = 0 To jresults.Size-1
            Dim m2 As Map = jresults.Get(k)
            Dim itk As Long = m2.Get("input_tokens")
            Tot_itk = Tot_itk + itk
            Dim otk As Long = m2.Get("output_tokens")
            Tot_otk = Tot_otk + otk
            Dim mdr As Long = m2.Get("num_model_requests")
            Tot_mod = Tot_mod + mdr
            If verbose Then
                'Log(jresults.Size)
                Log($"Input Tokens in bucket: ${itk}"$)
                Log($"Output Token in bucket: ${otk}"$)
                Log($"Model Requests in bucket: ${mdr}"$)
            End If
        Next
    Next
    
    Dim jmore As Boolean = root.Get("has_more")
    Dim jnextp As String = root.Get("next_page")
    
    Dim res As Map
    res.Initialize
    res.Put("more", jmore)
    res.Put("np", jnextp)
    res.Put("itk", Tot_itk)
    res.Put("otk", Tot_otk)
    res.Put("mdr", Tot_mod)
    
    Return res
End Sub
</code>

An the calling code (clsChatGPT1 is the temporary name I gave to my class):
<code>
Private wrk_chat As clsChatGPT1
wrk_chat.Initialize(False)

DateTime.DateFormat = "dd/MM/yyyy HH:mm:ss"
Dim ticks As Long = DateTime.DateParse("01/02/2025 00:00:01")
Dim Uticks As Long = DateUtils.TicksToUnixTime(ticks)                        'start time in Unix time format
Dim ticks As Long = DateTime.DateParse("03/02/2025 23:59:00")
Dim U2ticks As Long = DateUtils.TicksToUnixTime(ticks)                        'end time in Unix time format
Wait For (wrk_chat.QueryUsage(Uticks, U2ticks)) Complete (totals As Map)
LogColor($"Total Input Tokens: ${totals.Get("itk")}"$, 0xFFFF0000)
LogColor($"Total Output Tokens: ${totals.Get("otk")}"$, 0xFFFF0000)
LogColor($"Total Model Requests: ${totals.Get("mdr")}"$, 0xFFFF0000)
</code>
 
Top