@@ -2,6 +2,7 @@ module OpenAI
22
33using JSON3
44using HTTP
5+ using Dates
56
67abstract type AbstractOpenAIProvider end
78Base. @kwdef struct OpenAIProvider <: AbstractOpenAIProvider
@@ -15,15 +16,53 @@ Base.@kwdef struct AzureProvider <: AbstractOpenAIProvider
1516 api_version:: String = " 2023-03-15-preview"
1617end
1718
18- const DEFAULT_PROVIDER = OpenAIProvider ()
19+ """
20+ DEFAULT_PROVIDER
21+
22+ Default provider for OpenAI API requests.
23+ """
24+ const DEFAULT_PROVIDER = let
25+ api_key = get (ENV , " OPENAI_API_KEY" , nothing )
26+ if api_key === nothing
27+ OpenAIProvider ()
28+ else
29+ OpenAIProvider (api_key= api_key)
30+ end
31+ end
32+
33+ """
34+ auth_header(provider::AbstractOpenAIProvider, api_key::AbstractString)
1935
20- auth_header (provider:: AbstractOpenAIProvider , api_key:: AbstractString ) = error (" auth_header not implemented for $(typeof (provider)) " )
21- auth_header (provider:: OpenAIProvider , api_key:: AbstractString = provider. api_key) = [" Authorization" => " Bearer $(isempty (api_key) ? provider. api_key : api_key) " , " Content-Type" => " application/json" ]
22- auth_header (provider:: AzureProvider , api_key:: AbstractString = provider. api_key) = [" api-key" => (isempty (api_key) ? provider. api_key : api_key), " Content-Type" => " application/json" ]
36+ Return the authorization header for the given provider and API key.
37+ """
38+ auth_header (provider:: AbstractOpenAIProvider ) = auth_header (provider, provider. api_key)
39+ function auth_header (:: OpenAIProvider , api_key:: AbstractString )
40+ isempty (api_key) && throw (ArgumentError (" api_key cannot be empty" ))
41+ [
42+ " Authorization" => " Bearer $api_key " ,
43+ " Content-Type" => " application/json"
44+ ]
45+ end
46+ function auth_header (:: AzureProvider , api_key:: AbstractString )
47+ isempty (api_key) && throw (ArgumentError (" api_key cannot be empty" ))
48+ [
49+ " api-key" => api_key,
50+ " Content-Type" => " application/json"
51+ ]
52+ end
2353
24- build_url (provider:: AbstractOpenAIProvider , api:: String ) = error (" build_url not implemented for $(typeof (provider)) " )
25- build_url (provider:: OpenAIProvider , api:: String ) = " $(provider. base_url) /$(api) "
54+ """
55+ build_url(provider::AbstractOpenAIProvider, api::AbstractString)
56+
57+ Return the URL for the given provider and API.
58+ """
59+ build_url (provider:: AbstractOpenAIProvider ) = build_url (provider, provider. api)
60+ function build_url (provider:: OpenAIProvider , api:: String )
61+ isempty (api) && throw (ArgumentError (" api cannot be empty" ))
62+ " $(provider. base_url) /$(api) "
63+ end
2664function build_url (provider:: AzureProvider , api:: String )
65+ isempty (api) && throw (ArgumentError (" api cannot be empty" ))
2766 (; base_url, api_version) = provider
2867 return " $(base_url) /$(api) ?api-version=$(api_version) "
2968end
@@ -321,6 +360,83 @@ function create_images(api_key::String, prompt, n::Integer=1, size::String="256x
321360 return openai_request (" images/generations" , api_key; method= " POST" , http_kwargs= http_kwargs, prompt, kwargs... )
322361end
323362
363+ # api usage status
364+
365+ """
366+ get_usage_status(provider::OpenAIProvider; numofdays::Int=99)
367+
368+ Get usage status for the last `numofdays` days.
369+
370+ # Arguments:
371+ - `provider::OpenAIProvider`: OpenAI provider object.
372+ - `numofdays::Int`: Optional. Defaults to 99. The number of days to get usage status for.
373+ Note that the maximum `numofdays` is 99.
374+
375+ # Returns:
376+ - `quota`: The total quota for the subscription.(unit: USD)
377+ - `usage`: The total usage for the subscription.(unit: USD)
378+ - `daily_costs`: The daily costs for the subscription.
379+
380+ Each element of `daily_costs` looks like this:
381+ ```
382+ {
383+ "timestamp": 1681171200,
384+ "line_items": [
385+ {
386+ "name": "Instruct models",
387+ "cost": 0
388+ },
389+ {
390+ "name": "Chat models",
391+ "cost": 0
392+ },
393+ {
394+ "name": "GPT-4",
395+ "cost": 0
396+ },
397+ {
398+ "name": "Fine-tuned models",
399+ "cost": 0
400+ },
401+ {
402+ "name": "Embedding models",
403+ "cost": 0
404+ },
405+ {
406+ "name": "Image models",
407+ "cost": 0
408+ },
409+ {
410+ "name": "Audio models",
411+ "cost": 0
412+ }
413+ ]
414+ }
415+ ```
416+ """
417+ function get_usage_status (provider:: OpenAIProvider ; numofdays:: Int = 99 )
418+ (; base_url, api_key) = provider
419+ isempty (api_key) && throw (ArgumentError (" api_key cannot be empty" ))
420+ numofdays > 99 && throw (ArgumentError (" numofdays cannot be greater than 99" ))
421+
422+ # Get total quota from subscription_url
423+ subscription_url = " $base_url /dashboard/billing/subscription"
424+ subscrip = HTTP. get (subscription_url, headers = auth_header (provider))
425+ resp = OpenAIResponse (subscrip. status, JSON3. read (subscrip. body))
426+ # TODO : catch error
427+ quota = resp. response. hard_limit_usd
428+
429+ # Get usage status from billing_url
430+ start_date = today ()
431+ end_date = today () + Day (numofdays)
432+ billing_url = " $base_url /dashboard/billing/usage?start_date=$(start_date) &end_date=$(end_date) "
433+ billing = HTTP. get (billing_url, headers = auth_header (provider))
434+ resp = OpenAIResponse (billing. status, JSON3. read (billing. body))
435+ usage = resp. response. total_usage / 100
436+ daily_costs = resp. response. daily_costs
437+ return (; quota, usage, daily_costs)
438+ end
439+
324440export OpenAIResponse
325441export list_models
326442export retrieve_model
@@ -329,5 +445,6 @@ export create_completion
329445export create_edit
330446export create_embeddings
331447export create_images
448+ export get_usage_status
332449
333450end # module
0 commit comments