Module: LlmCostTracker::Parsers::OpenaiUsage

Includes:
OpenaiServiceCharges
Included in:
Azure, Openai, OpenaiCompatible
Defined in:
lib/llm_cost_tracker/parsers/openai_usage.rb

Constant Summary

Constants included from OpenaiServiceCharges

LlmCostTracker::Parsers::OpenaiServiceCharges::CHAT_COMPLETIONS_ANNOTATION_PROVIDER_FIELD, LlmCostTracker::Parsers::OpenaiServiceCharges::CHAT_COMPLETIONS_SEARCH_MODEL_PROVIDER_FIELD, LlmCostTracker::Parsers::OpenaiServiceCharges::RESPONSE_OUTPUT_COMPONENTS

Class Method Summary collapse

Instance Method Summary collapse

Methods included from OpenaiServiceCharges

billable?, build_line_item, chat_completions_search_model?, chat_completions_search_provider_field, chat_completions_used_web_search?, chat_completions_web_search_items, component_key_for, line_item_details, line_items_from_output, openai_stream_service_line_items, reasoning_model?, service_line_items_for, store_output_item, web_search_preview_used?

Class Method Details

.combined_pricing_mode(host:, model:, service_tier:) ⇒ Object



13
14
15
16
17
18
# File 'lib/llm_cost_tracker/parsers/openai_usage.rb', line 13

def combined_pricing_mode(host:, model:, service_tier:)
  modes = [Pricing.normalize_mode(service_tier)]
  modes << "data_residency" if regional_processing?(host: host, model: model)
  modes = modes.compact.uniq
  modes.empty? ? nil : modes.join("_")
end

.regional_processing?(host:, model:) ⇒ Boolean

Returns:

  • (Boolean)


20
21
22
23
# File 'lib/llm_cost_tracker/parsers/openai_usage.rb', line 20

def regional_processing?(host:, model:)
  LlmCostTracker::Providers::Openai::Hosts.data_residency?(host) &&
    LlmCostTracker::Providers::Openai::ModelFamilies.data_residency?(model)
end

Instance Method Details

#auto_enable_stream_usage?(request_url) ⇒ Boolean

Returns:

  • (Boolean)


66
67
68
# File 'lib/llm_cost_tracker/parsers/openai_usage.rb', line 66

def auto_enable_stream_usage?(request_url)
  openai_chat_completions_url?(request_url)
end

#parse(request_url:, request_body:, response_status:, response_body:) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/llm_cost_tracker/parsers/openai_usage.rb', line 26

def parse(request_url:, request_body:, response_status:, response_body:, **)
  return nil unless response_status == 200

  response = safe_json_parse(response_body)
  usage = response["usage"]
  return nil unless usage

  request = safe_json_parse(request_body)
  cache_read = cache_read_input_tokens(usage)

  model = response["model"] || request["model"]

  Event.build(
    provider: provider_for(request_url),
    provider_response_id: response["id"],
    pricing_mode: pricing_mode(
      request_url: request_url,
      model: model,
      service_tier: response["service_tier"] || request["service_tier"]
    ),
    model: model,
    token_usage: token_usage(usage: usage, cache_read: cache_read, model: model),
    usage_source: :response,
    service_line_items: service_line_items_for(response, request: request, model: response["model"])
  )
end

#parse_stream(response_status:, request_url: nil, request_body: nil, events: []) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/llm_cost_tracker/parsers/openai_usage.rb', line 53

def parse_stream(response_status:, request_url: nil, request_body: nil, events: [], **)
  return nil unless response_status == 200

  request = safe_json_parse(request_body)
  usage = detect_stream_usage(events)
  context = stream_capture_context(events: events, request: request, request_url: request_url)

  return build_known_stream_usage(usage: usage, **context) if usage

  warn_missing_stream_usage(request_url: request_url, request: request)
  build_unknown_stream_usage(**context)
end